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

时间:2015-03-30 20:56:55

标签: c# .net async-await task-parallel-library thread-sleep

我最近看到一些建议,指出永远不应在生产代码中使用Thread.Sleep(最近在this SO question中)。其中许多人主张使用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);
}

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

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

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

1 个答案:

答案 0 :(得分:7)

替换Thread.Sleep(1000);中的Task.Delay(1000).Wait();绝非易事。如果您想要同步等待,请使用Thread.Sleep

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

您也可以直接使用System.Threading.Timer * 而不是Task.Delay但是请记住,计时器会执行每个间隔而不会等待实际操作要完成,所以如果ExternalServiceIsReady占用的时间超过间隔,则可以同时多次调用该服务。

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

await ExternalServiceIsReadyAsync();

* Task.Delay内部使用System.Threading.Timer,其分辨率约为15毫秒。