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

问题描述 投票:282回答:4

什么时候使用Task.DelayThread.Sleep有很好的规则?

  • 具体来说,是否有一个最小值来提供一个有效/高效的另一个?
  • 最后,由于Task.Delay导致异步/等待状态机上下文切换,是否有使用它的开销?
c# multithreading task-parallel-library
4个回答
289
投票

如果要阻止当前线程,请使用Thread.Sleep

如果需要逻辑延迟而不阻塞当前线程,请使用Task.Delay

效率不应成为这些方法的首要考虑因素。它们的主要实际用途是作为I / O操作的重试计时器,其大小为秒而不是毫秒。


183
投票

Task.DelayThread.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释放它在你等待时做其他工作。


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

我也同意效率在这种情况下并不是最重要的。


20
投票

我想补充一些东西。实际上,Task.Delay是一个基于计时器的等待机制。如果你看看source,你会找到一个Timer类的参考,它负责延迟。另一方面,Thread.Sleep实际上使当前线程进入睡眠状态,这样你只是阻塞并浪费一个线程。在异步编程模型中,如果你想在延迟之后发生某些事情(延续),你应该总是使用Task.Delay()

© www.soinside.com 2019 - 2024. All rights reserved.