Reputation: 1096
I've created a test program that runs 1000 Tasks which perform Task.Delay
with a random delay between 20s and 30s.
It looks like cancelling this operation takes about 10s..
Here is my test program :
class Program
{
static async Task MainAsync()
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
List<Task> allTask = new List<Task>();
Random r = new Random(9);
async Task SafeDelay(int delay, CancellationToken token)
{
try
{
await Task.Delay(delay, token);
}
catch (TaskCanceledException)
{
}
}
for (int i = 0; i < 1000; i++)
{
var randomDelay = r.Next(20000, 30000);
allTask.Add(SafeDelay(randomDelay, tokenSource.Token));
;
}
Stopwatch stopwatch = new Stopwatch();
var cancelTask = Task.Delay(1000).ContinueWith(t =>
{
Console.Out.WriteLine("1000ms elapsed. Cancelation request start");;
stopwatch.Start();
tokenSource.Cancel();
});
await Task.WhenAll(allTask);
await cancelTask;
stopwatch.Stop();
Console.WriteLine($"Cancelation done after {stopwatch.ElapsedMilliseconds} ms");
}
static void Main(string[] args)
{
Console.WriteLine("Started");
Task.Run(MainAsync).GetAwaiter().GetResult();
Console.WriteLine("End");
Console.ReadLine();
}
}
My Result with .NET Core 2.1:
Cancelation done after 9808ms
Why is cancelling Task.Delay so slow and is there a way to improve it?
My Result with .NET 4.7.1:
Cancelation done after 6200ms
Upvotes: 2
Views: 436
Reputation: 273591
When I run this with F5 I get a similar result.
Run it with Ctrl+F5 (no debugger) and it cancels in less than 50 ms.
So you are actually timing 1000 execptions tickling the debugger. The debugger might intefere with other execution points too. Always run benchmarks in Release Mode, w/o a debugger.
Upvotes: 7
Reputation: 131706
No repro with the question's code. Using it as is, I get :
Started
1000ms elapsed. Cancelation request start
Cancelation done after 38 ms
End
No repro with cleaned up code :
static async Task SafeDelay(int delay, CancellationToken token)
{
try
{
await Task.Delay(delay, token);
}
catch (TaskCanceledException)
{
}
}
private static async Task Main()
{
//Set 1000 ms timeout
var tokenSource = new CancellationTokenSource(1000);
var stopwatch = Stopwatch.StartNew();
var allTask = new List<Task>();
Random r = new Random(9);
for (var i = 0; i < 1000; i++)
{
var randomDelay = r.Next(20000, 30000);
allTask.Add(SafeDelay(randomDelay, tokenSource.Token));
}
Console.WriteLine($"All {allTask.Count} tasks running after {stopwatch.ElapsedMilliseconds} ms");
await Task.WhenAll(allTask);
stopwatch.Stop();
Console.WriteLine($"Cancelation done after {stopwatch.ElapsedMilliseconds} ms");
}
This produces :
All 1000 tasks running after 8 ms
Cancelation done after 1044 ms
The CancellationTokenSource has a 1000ms timeout.
Upvotes: 1