线程.睡眠与任务.延迟
本文关键字:任务 延迟 线程 | 更新日期: 2023-09-27 18:19:44
我知道Thread.Sleep
阻塞了一个线程。
但是Task.Delay
也会阻止吗?还是就像Timer
一样对所有回调使用一个线程(不重叠时(?
(这个问题不包括差异(
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 个线程。显然这没有发生。