我是不是应该始终使用 Task.Delay 而不是 Thread.Sleep? [复制]

Posted

技术标签:

【中文标题】我是不是应该始终使用 Task.Delay 而不是 Thread.Sleep? [复制]【英文标题】:Should I always use Task.Delay instead of Thread.Sleep? [duplicate]我是否应该始终使用 Task.Delay 而不是 Thread.Sleep? [复制] 【发布时间】:2015-03-30 20:56:54 【问题描述】:

我最近看到了一些建议,指出永远不要在生产代码中使用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 毫秒左右的典型计时器分辨率而言,睡眠时间相当长,因此 Task.Delay 的准确性提高似乎微不足道。 进程是单线程的(非UI),必须阻塞直到条件为真,所以在这里使用await没有优势。 不需要取消延迟的能力。

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

【问题讨论】:

ExternalServiceIsReady 是做什么的?也许可以完全避免睡眠/延迟。 是否有使用事件的选项 C?它可能比这种投票方式更合适。 选项 D 是更好的解决方案,一个计时器。 @HansPassant 你能详细说明为什么定时器是一个更好的解决方案吗? 无循环、无线程、无睡眠。 【参考方案1】:

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

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

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

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

await ExternalServiceIsReadyAsync();

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

【讨论】:

如果ExternalServiceIsReady 可以以不需要睡眠/等待的方式引发事件,则更好的方法是。 @EZI 这是异步的。 然后呢?它不是循环和睡眠吗?异步调用在这里改变了什么?你在这里只涉及另一个任务。 @i3arnon 对于您的最后一条评论:Thread.Sleep 不会浪费任何 CPU 周期。它保留了一个可用的资源(线程),但没有花费 cpu 周期。你的意思是while循环和那些条件? 又一个挑剔的人。 Task.Delay 创建一个Task(内存分配),task.Wait() 将旋转一段时间,task.Wait() 将在该点之后分配一个内核事件(内核资源和用户-> 内核转换)所有这些都会占用CPU周期:)

以上是关于我是不是应该始终使用 Task.Delay 而不是 Thread.Sleep? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

当我们在 Entity Framework Core 中拥有主键时,我们是不是应该始终使用 .Find() 而不是 .FirstOrDefault() ?

面向最终用户的表格是不是应该始终采用视图的形式?

如何对包含Task.Delay的代码进行单元测试?

何时使用Task.Delay,何时使用Thread.Sleep?

在 package.json 中使用 * 而不是版本号时如何始终获取最新版本? [复制]

NSFetchedResultsController 是不是应该始终与 Core Data 一起使用?