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

Should I always use Task.Delay instead of 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 的以下潜在优势似乎不适用:

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

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 毫秒。