是否有很好的规则来说明何时使用Task。Delay vs . Thread.Sleep?

具体来说,是否存在一个最小值来保证其中一个比另一个更有效? 最后,自从任务。延迟导致异步/等待状态机上的上下文切换,是否有使用它的开销?


当前回答

值得一提的是Thread.Sleep(1)将更快地触发GC。

This is purely based mine & team member observations. Lets assume that you have service which creates new task every for specific request (approx. 200-300 ongoing) and this task contains many weak references in flow. The task is working like state machine so we were firing the Thread.Sleep(1) on change state and by doing so we managed to optimize utilization of memory in the application - like I said before - this will makes GC to fire faster. It doesn't make so much difference in low memory consumption services (<1GB).

其他回答

我的观点,

Task.Delay()是异步的。它不会阻塞当前线程。您仍然可以在当前线程中执行其他操作。它返回一个Task返回类型(Thread.Sleep()不返回任何东西)。您可以检查该任务是否已完成(使用task。IsCompleted属性),稍后在另一个耗时的过程之后。

Thread.Sleep()没有返回类型。它是同步的。在线程中,除了等待延迟完成之外,您实际上不能做任何事情。

至于在现实生活中的使用,我已经编程15年了。我从未在产品代码中使用过Thread.Sleep()。我找不到任何用例。 也许是因为我主要从事web应用程序开发。

我想补充一点。 实际上,任务。Delay是一种基于定时器的等待机制。如果您查看源代码,您会发现一个Timer类的引用,它是造成延迟的原因。另一方面,线程。Sleep实际上使当前线程休眠,这样你只是阻塞和浪费了一个线程。在异步编程模型中,如果你想在延迟后发生某些事情(延续),你应该总是使用Task.Delay()。

任务之间最大的区别。延迟和线程。睡眠就是那个任务。Delay旨在异步运行。使用Task没有意义。同步代码中的延迟。使用线程是一个非常糟糕的主意。在异步代码中休眠。

通常你会用await关键字调用Task.Delay():

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延迟移到控制台上方。而是写入eline,它将打印运行5.0020168秒。

让我们看看Thread的不同之处。睡眠:

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");
    }
}

试着预测一下它会打印什么…

异步:开始 async:运行0.0070048秒 同步:开始 async:运行5.0119008秒 异步:完成 sync:运行5.0020168秒 同步:完成

另外,有趣的是注意到Thread。睡眠要精确得多,毫秒精度不是真正的问题,而任务。延迟最少需要15-30毫秒。与ms精度相比,这两个函数的开销是最小的(如果你需要更精确的东西,请使用Stopwatch Class)。线程。睡眠仍然束缚着你的线程,任务。在等待的同时,延迟释放它以做其他工作。

如果当前线程被杀死,你使用thread。Sleep并且它正在执行,那么你可能会得到一个ThreadAbortException。 与任务。延迟您总是可以提供一个取消令牌并优雅地终止它。这就是我选择Task.Delay的原因之一。参见http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx

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

使用线程。当您想要阻塞当前线程时休眠。

使用await Task。延迟:当您希望在不阻塞当前线程的情况下进行逻辑延迟时。

效率不应该是这些方法的首要考虑因素。它们在现实世界中的主要用途是作为I/O操作的重试计时器,其数量级为秒而不是毫秒。