我是不是应该始终使用 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
的以下潜在优势似乎并不适用:
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,何时使用Thread.Sleep?