是否有何时使用Task.Delay和Thread.Sleep的良好规则?
- 具体来说,是否存在一个最小值,以使其中一个比另一个有效/高效?
- 最后,由于Task.Delay导致在异步/等待状态机上进行上下文切换,因此使用它会产生开销吗?
是否有何时使用Task.Delay和Thread.Sleep的良好规则?
Answers:
使用Thread.Sleep
时要阻止当前线程。
使用Task.Delay
时,你想不阻塞当前线程的逻辑延迟。
对于这些方法,效率不应该是最重要的问题。它们在现实世界中的主要用途是作为I / O操作的重试计时器,其数量级为秒而不是毫秒。
Thread.Sleep
将阻止当前线程,这会导致上下文切换。如果使用线程池,这也可能导致分配新线程。两种操作都非常繁重,而Task.Delay
etc等提供的协作式多任务设计旨在避免所有这些开销,最大化吞吐量,允许取消并提供更简洁的代码。
onesi: I would use
Thread.Sleep`在同步方法中等待。但是,我从未在生产代码中这样做;以我的经验,Thread.Sleep
我所见过的每件事都表明某种设计问题需要适当解决。
最大的区别Task.Delay
和Thread.Sleep
的是,Task.Delay
旨在异步运行。Task.Delay
在同步代码中使用没有意义。Thread.Sleep
在异步代码中使用是一个非常糟糕的主意。
通常,您将Task.Delay()
使用await
关键字进行呼叫:
await Task.Delay(5000);
或者,如果您想在延迟之前运行一些代码:
var sw = new Stopwatch();
sw.Start();
Task delay = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await delay;
猜猜这将打印什么?运行0.0070048秒。如果将鼠标移到await delay
上方Console.WriteLine
,它将显示运行时间5.0020168秒。
让我们看看与的区别Thread.Sleep
:
class Program
{
static void Main(string[] args)
{
Task delay = asyncTask();
syncCode();
delay.Wait();
Console.ReadLine();
}
static async Task asyncTask()
{
var sw = new Stopwatch();
sw.Start();
Console.WriteLine("async: Starting");
Task delay = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await delay;
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine("async: Done");
}
static void syncCode()
{
var sw = new Stopwatch();
sw.Start();
Console.WriteLine("sync: Starting");
Thread.Sleep(5000);
Console.WriteLine("sync: Running for {0} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine("sync: Done");
}
}
尝试预测将要打印的内容...
异步:启动
异步:运行0.0070048秒
同步:启动
异步:运行5.0119008秒
异步:完成
同步:运行5.0020168秒
同步:完成
另外,有趣的是,它的Thread.Sleep
准确性要高得多,ms的准确性并不是真正的问题,而Task.Delay
最小的时间为15-30ms。与它们具有的ms精度相比,这两个函数的开销是最小的(Stopwatch
如果需要更准确的信息,请使用Class)。Thread.Sleep
仍然束缚您的线程,Task.Delay
在等待时释放它以执行其他工作。
Thread.Sleep()
会消耗整个线程,而该线程本可以在其他地方使用。如果使用Thread.Sleep()运行许多任务,则很有可能耗尽所有线程池线程并严重影响性能。
async
鼓励使用方法的意义上,我缺少异步代码的概念。Thread.Sleep()
在线程池线程中运行基本上是一个坏主意,而不是一般的坏主意。毕竟,有TaskCreationOptions.LongRunning
(尽管不鼓励)Task.Factory.StartNew()
路线。
await wait
Tasl.Delay
使用系统计时器。由于“系统时钟以固定速率“滴答”。”,系统计时器的滴答速度约为16毫秒,因此您请求的任何延迟都将四舍五入为系统时钟滴答的数目,并偏移直到第一个滴答滴答的时间。蜱。请参阅Task.Delay
docs.microsoft.com/zh-cn/dotnet/api/…上的msdn文档,然后向下滚动至备注。
如果当前线程被杀死并且您使用Thread.Sleep
并且正在执行,那么您可能会得到一个ThreadAbortException
。有了Task.Delay
可以随时提供取消标记,并优雅地杀死它。那就是我会选择的原因之一Task.Delay
。参见http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx
我也同意在这种情况下效率不是最重要的。
await Task.Delay(5000)
。当我杀死任务时,我得到了TaskCanceledException
(并抑制了任务),但是我的线程仍然存在。整齐!:)
我要添加一些东西。实际上,这Task.Delay
是一个基于计时器的等待机制。如果您查看源代码,则会发现Timer
对导致延迟的类的引用。另一方面,Thread.Sleep
实际上使当前线程进入睡眠状态,那样您就阻塞并浪费了一个线程。在异步编程模型中,Task.Delay()
如果您希望某些(连续)延迟后发生,则应始终使用。