MSDN 上的文档令人失望,但使用 Reflector 反编译 Task.Delay
可以获得更多信息:
public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken)
{
if (millisecondsDelay < -1)
{
throw new ArgumentOutOfRangeException("millisecondsDelay", Environment.GetResourceString("Task_Delay_InvalidMillisecondsDelay"));
}
if (cancellationToken.IsCancellationRequested)
{
return FromCancellation(cancellationToken);
}
if (millisecondsDelay == 0)
{
return CompletedTask;
}
DelayPromise state = new DelayPromise(cancellationToken);
if (cancellationToken.CanBeCanceled)
{
state.Registration = cancellationToken.InternalRegisterWithoutEC(delegate (object state) {
((DelayPromise) state).Complete();
}, state);
}
if (millisecondsDelay != -1)
{
state.Timer = new Timer(delegate (object state) {
((DelayPromise) state).Complete();
}, state, millisecondsDelay, -1);
state.Timer.KeepRootedWhileScheduled();
}
return state;
}
基本上,这种方法只是一个包装在任务内部的计时器。因此,你可以说它就像计时器一样。
Task.Delay
不会阻塞当前线程。它可以用来阻塞线程,但它本身并不会这样做,在实践中很少用作同步阻塞器。它实际上只是返回一个在指定时间后完成的Task
:Task task = Task.Delay(1000); // The task will complete after 1,000 milliseconds.
通常,这个任务会在async
方法内使用await
关键字进行异步等待:
await task; // Suspends the async method, but doesn't block the thread.
await
关键字会暂停当前执行流程(异步方法),直到可等待对象完成。在执行流程被暂停时,没有线程被阻塞。Wait
方法来阻塞当前线程,直到任务完成。task.Wait(); // Blocks the thread.
await Task.Delay()
不会阻塞线程,这里有一个。下面的程序创建了大量的任务,其中每个任务都在内部等待 Task.Delay(1000)
。然后,在控制台中打印当前进程使用的 线程数量,最后等待所有任务完成:Task[] tasks = Enumerable.Range(1, 100_000).Select(async _ =>
{
await Task.Delay(1000);
}).ToArray();
Console.WriteLine($"Tasks: {tasks.Count(t => t.IsCompleted):#,0} / {tasks.Length:#,0}");
Thread.Sleep(500);
Console.WriteLine($"Threads.Count: {Process.GetCurrentProcess().Threads.Count:#,0}");
await Task.WhenAll(tasks);
Console.WriteLine($"Tasks: {tasks.Count(t => t.IsCompleted):#,0} / {tasks.Length:#,0}");
输出:
Tasks: 0 / 100,000
Threads.Count: 9
Tasks: 100,000 / 100,000
在线演示。
程序只用了1秒钟就完成了,并报告在峰值时使用了总共9个线程。如果每个100,000个任务都阻塞一个线程,我们预计会在那个时候看到使用100,000个线程。显然,这并没有发生。
ThreadPool
中的一个线程。因此,ThreadPool
创建了一些线程来满足需求,可能是4个线程。这可以解释总线程数从9增加到13的原因。我对第14个线程没有理论。 - Theodor Zoulias