是否有很好的规则来说明何时使用Task。Delay vs . Thread.Sleep?
具体来说,是否存在一个最小值来保证其中一个比另一个更有效? 最后,自从任务。延迟导致异步/等待状态机上的上下文切换,是否有使用它的开销?
是否有很好的规则来说明何时使用Task。Delay vs . Thread.Sleep?
具体来说,是否存在一个最小值来保证其中一个比另一个更有效? 最后,自从任务。延迟导致异步/等待状态机上的上下文切换,是否有使用它的开销?
当前回答
我的观点,
Task.Delay()是异步的。它不会阻塞当前线程。您仍然可以在当前线程中执行其他操作。它返回一个Task返回类型(Thread.Sleep()不返回任何东西)。您可以检查该任务是否已完成(使用task。IsCompleted属性),稍后在另一个耗时的过程之后。
Thread.Sleep()没有返回类型。它是同步的。在线程中,除了等待延迟完成之外,您实际上不能做任何事情。
至于在现实生活中的使用,我已经编程15年了。我从未在产品代码中使用过Thread.Sleep()。我找不到任何用例。 也许是因为我主要从事web应用程序开发。
其他回答
我和一位同事为此争论了很长时间,他向我证明,在上面的答案目前所显示的范围之外,还有显著的差异。如果你等待Task.Delay(somemillisecseconds),你实际上可以释放堆栈上的直接父对象之外的调用者:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Started " + Thread.CurrentThread.ManagedThreadId);
DoSomething1();
Console.WriteLine("Finished " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(6000);
}
static async void DoSomething1()
{
Console.WriteLine("DoSomething1 Started " + Thread.CurrentThread.ManagedThreadId);
var result = await DoSomething2();
Console.WriteLine("DoSomething1 Finished " + Thread.CurrentThread.ManagedThreadId);
}
static async Task<int> DoSomething2()
{
Console.WriteLine("DoSomething2 Started " + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(5000); // Will block DoSomething1 but release Main
//Thread.Sleep(5000); // Will block everything including Main
//await Task.FromResult(5); // Will return immediately (just for comparison)
//await Task.Delay(0); // What will it do, can you guess?
Console.WriteLine("DoSomething2 Finished " + Thread.CurrentThread.ManagedThreadId);
return 0;
}
}
}
玩一下这段代码,观察使用Delay或Sleep的不同效果。这个解释超出了这个答案的范围,但可以总结为“异步函数不会启动另一个线程,直到它们等待一些不能立即运行的东西(或结果确定)”。输出如下:
Started 1
DoSomething1 Started 1
DoSomething2 Started 1
Finished 1
DoSomething2 Finished 4
DoSomething1 Finished 4
这不是关于DoSomething1();在Main被大火遗忘。你可以用Sleep来证明这一点。还要观察当DoSomething2从Task“返回”时。延迟,它在另一个线程上运行。
这个东西比我给它的信用要聪明得多,相信await只是开始了一个新的线程来做事情。我仍然没有假装完全理解,但上面的反直觉结果表明,在底层有更多的事情要做,而不仅仅是启动线程来运行代码。
是的,对于何时使用Task有一些一般的指导方针。Delay vs . Thread.Sleep。的任务。延迟是c#中异步编程的首选方法,因为它允许您在不阻塞线程的情况下异步等待。线程。Sleep阻塞调用线程,并可能导致高并发性应用程序的性能问题。
Task没有最小值。延迟对Thread.Sleep有效。一般来说,如果你需要等待一定的时间,最好使用Task.Delay。如果你需要在特定的时间内阻塞一个线程,请使用thread . sleep。
至于使用Task的开销。在异步/等待状态机中,上下文切换涉及一些开销。但是,开销通常很小,而且异步编程的好处远远超过了它。当使用Task。正确地延迟,它可以帮助提高应用程序的响应性和可伸缩性。
使用线程。当您想要阻塞当前线程时休眠。
使用await Task。延迟:当您希望在不阻塞当前线程的情况下进行逻辑延迟时。
效率不应该是这些方法的首要考虑因素。它们在现实世界中的主要用途是作为I/O操作的重试计时器,其数量级为秒而不是毫秒。
我想补充一点。 实际上,任务。Delay是一种基于定时器的等待机制。如果您查看源代码,您会发现一个Timer类的引用,它是造成延迟的原因。另一方面,线程。Sleep实际上使当前线程休眠,这样你只是阻塞和浪费了一个线程。在异步编程模型中,如果你想在延迟后发生某些事情(延续),你应该总是使用Task.Delay()。
如果当前线程被杀死,你使用thread。Sleep并且它正在执行,那么你可能会得到一个ThreadAbortException。 与任务。延迟您总是可以提供一个取消令牌并优雅地终止它。这就是我选择Task.Delay的原因之一。参见http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx
我也同意在这种情况下效率不是最重要的。