我应该总是使用Task.Delay而不是Thread.Sleep吗?

BJ *_*ers 4 .net c# task-parallel-library async-await thread-sleep

我最近看到了几条建议,说Thread.Sleep永远不应该在生产代码中使用(最近在这个SO问题中).其中许多人主张使用Task.Delay.我发现的大多数解释都使用UI应用程序作为示例,因为Task.Delay显而易见的优点(不阻止UI).

在我的情况下,我Thread.Sleep在一个等待循环内部使用轮询WCF服务的特定条件,如下所示:

DateTime end = DateTime.UtcNow + TimeSpan.FromMinutes(2);
while (DateTime.UtcNow < end)
{
    if (ExternalServiceIsReady() == true)
    {
        return true;
    }
    Thread.Sleep(1000);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,以下潜在优势Task.Delay似乎不适用:

  • 睡眠时间相对于大约15毫秒的典型定时器分辨率相当大,因此准确度的提高Task.Delay似乎微不足道.
  • 该进程是单线程(非UI),必须阻塞直到条件为真,因此使用await在这里没有任何优势.
  • 不需要取消延迟的能力.

这是适合使用的情况Thread.Sleep吗?用替换我的睡眠线有Task.Delay(1000).Wait()什么好处(如果有的话)?

i3a*_*non 7

替换Thread.Sleep(1000);中从来没有优势Task.Delay(1000).Wait();.如果你想同步等待使用Thread.Sleep.

如果你真的只有一个线程并计划保持这种方式,那么你可以使用Thread.Sleep.但是,Task.Delay在大多数情况下,我仍然会使用它,因此这是一个很好的模式.当你不能再使用时,我只会阻止在最顶层async,即便如此,我建议使用某种AsyncContext.

您也可以System.Threading.Timer直接使用*而不是,Task.Delay但是您应该记住,计时器执行每个时间间隔并且不等待实际操作完成,因此如果ExternalServiceIsReady超过时间间隔,您可以同时多次调用该服务.

一个更好的解决方案是用异步操作替换外部服务的轮询,这样服务就可以在它准备就绪时通知你而不是你每秒都要求它(这并不总是可能的,因为它取决于服务):

await ExternalServiceIsReadyAsync();
Run Code Online (Sandbox Code Playgroud)

* 内部Task.Delay使用System.Threading.Timer,分辨率约为15ms.

  • 如果`ExternalServiceIsReady`可以抛出一个不需要睡眠/等待的事件,那么更好的方法就是这样. (2认同)
  • 另一个挑剔。`Task.Delay` 创建一个 `Task`(内存分配),`task.Wait()` 将旋转一定的时间,`task.Wait()` 将在该点之后分配一个内核事件(内核资源和用户-&gt; 内核转换)所有这些都需要 CPU 周期:) (2认同)