何时使用Task.Delay与Thread.Sleep有合适的规则?
答案 0 :(得分:294)
如果要阻止当前线程,请使用Thread.Sleep
。
如果您想要逻辑延迟而不阻止当前线程,请使用Task.Delay
。
效率不应成为这些方法的首要考虑因素。它们的主要实际用途是作为I / O操作的重试计时器,其大小为秒而不是毫秒。
答案 1 :(得分:189)
Task.Delay
和Thread.Sleep
之间的最大区别是Task.Delay
旨在异步运行。在同步代码中使用Task.Delay
没有意义。在异步代码中使用Thread.Sleep
是一个非常糟糕的主意。
通常,您会使用Task.Delay()
关键字致电await
:
await Task.Delay(5000);
或者,如果你想在延迟之前运行一些代码:
var sw = new Stopwatch();
sw.Start();
Task delay = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await delay;
猜猜这会打印什么?运行0.0070048秒。
如果我们将await delay
移到Console.WriteLine
之上,它将打印运行5.0020168秒。
让我们看一下与Thread.Sleep
的区别:
class Program
{
static void Main(string[] args)
{
Task delay = asyncTask();
syncCode();
delay.Wait();
Console.ReadLine();
}
static async Task asyncTask()
{
var sw = new Stopwatch();
sw.Start();
Console.WriteLine("async: Starting");
Task delay = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await delay;
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine("async: Done");
}
static void syncCode()
{
var sw = new Stopwatch();
sw.Start();
Console.WriteLine("sync: Starting");
Thread.Sleep(5000);
Console.WriteLine("sync: Running for {0} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine("sync: Done");
}
}
尝试预测会打印什么......
异步:开始
异步:运行0.0070048秒
同步:开始
异步:运行5.0119008秒
异步:完成
同步:运行5.0020168秒
同步:完成
另外,有趣的是注意Thread.Sleep
更准确,ms准确度不是真正的问题,而Task.Delay
可能需要15-30ms。两个函数的开销与它们具有的ms精度相比是最小的(如果您需要更精确的东西,请使用Stopwatch
类)。 Thread.Sleep
仍然绑定你的主题,Task.Delay
释放它以便在你等待时做其他工作。
答案 2 :(得分:26)
如果当前线程被终止并且您使用Thread.Sleep
并且它正在执行,那么您可能会获得ThreadAbortException
。
使用Task.Delay
,您始终可以提供取消令牌并优雅地将其删除。这就是我选择Task.Delay
的一个原因。见http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx
我也同意效率在这种情况下并不是最重要的。
答案 3 :(得分:20)
我想补充一些东西。
实际上,Task.Delay
是基于计时器的等待机制。如果您查看source,您会找到对Timer
类的引用,该类负责延迟。另一方面,Thread.Sleep
实际上使当前线程处于休眠状态,这样你只是阻塞并浪费一个线程。在异步编程模型中,如果你想在某些延迟后发生某些事情(延续),你应该总是使用Task.Delay()
。
答案 4 :(得分:1)
Delayed
将是 Task.Delay
的更好名称 - 因为它不会延迟现有任务,而是创建一个新的“延迟”任务,另一方面可以等待并导致暂停到当前任务的正文。它本质上是一个计时器,但没有回调/主体。
等待延迟任务会在异步消息队列中创建一个新项目,并且不会阻塞任何线程。调用 await 的同一线程将继续处理其他任务(如果有的话),并在超时后(或队列中的前面的项目完成时)返回到等待点。引擎盖下的任务使用线程 - 可以在单个线程中调度和执行许多任务。另一方面,如果您碰巧调用 Thread.Sleep()
,线程将被阻塞,即它将在请求的时间内停止运行,并且不会处理队列中的任何异步消息。
在 .NET 中,有两种主要的并行方法。旧的有线程、线程池等。新的基于任务、异步/等待、TPL。根据经验,您不要混合使用这两个领域的 API。
答案 5 :(得分:0)
还值得一提的是,Thread.Sleep(1) 会更快地触发 GC。
<块引用>这纯粹是基于我和团队成员的观察。让我们假设 你有为特定请求创建新任务的服务 (大约 200-300 正在进行)并且此任务包含许多弱引用 在流动。任务像状态机一样工作,所以我们正在触发 Thread.Sleep(1) 改变状态,通过这样做我们设法优化 应用程序中的内存利用率 - 就像我之前说的 - 这 将使 GC 启动得更快。它没有太大区别 低内存消耗服务 (<1GB)。
答案 6 :(得分:-3)
我的看法,
Task.Delay()
是异步的。它不会阻止当前线程。您仍然可以在当前线程中执行其他操作。它返回Task返回类型(Thread.Sleep()
不返回任何值)。在另一个耗时的过程之后,您可以稍后检查此任务是否完成(使用Task.IsCompleted
属性。
Thread.Sleep()
没有返回类型。它是同步的。在线程中,除了等待延迟完成之外,您什么都做不到。
对于现实生活中的使用,我已经编程15年了。我从未在生产代码中使用Thread.Sleep()
。我找不到任何用例。
也许是因为我主要从事Web应用程序开发。