是否有很好的规则来说明何时使用Task。Delay vs . Thread.Sleep?
具体来说,是否存在一个最小值来保证其中一个比另一个更有效? 最后,自从任务。延迟导致异步/等待状态机上的上下文切换,是否有使用它的开销?
是否有很好的规则来说明何时使用Task。Delay vs . Thread.Sleep?
具体来说,是否存在一个最小值来保证其中一个比另一个更有效? 最后,自从任务。延迟导致异步/等待状态机上的上下文切换,是否有使用它的开销?
当前回答
是的,对于何时使用Task有一些一般的指导方针。Delay vs . Thread.Sleep。的任务。延迟是c#中异步编程的首选方法,因为它允许您在不阻塞线程的情况下异步等待。线程。Sleep阻塞调用线程,并可能导致高并发性应用程序的性能问题。
Task没有最小值。延迟对Thread.Sleep有效。一般来说,如果你需要等待一定的时间,最好使用Task.Delay。如果你需要在特定的时间内阻塞一个线程,请使用thread . sleep。
至于使用Task的开销。在异步/等待状态机中,上下文切换涉及一些开销。但是,开销通常很小,而且异步编程的好处远远超过了它。当使用Task。正确地延迟,它可以帮助提高应用程序的响应性和可伸缩性。
其他回答
使用线程。当您想要阻塞当前线程时休眠。
使用await Task。延迟:当您希望在不阻塞当前线程的情况下进行逻辑延迟时。
效率不应该是这些方法的首要考虑因素。它们在现实世界中的主要用途是作为I/O操作的重试计时器,其数量级为秒而不是毫秒。
我的观点,
Task.Delay()是异步的。它不会阻塞当前线程。您仍然可以在当前线程中执行其他操作。它返回一个Task返回类型(Thread.Sleep()不返回任何东西)。您可以检查该任务是否已完成(使用task。IsCompleted属性),稍后在另一个耗时的过程之后。
Thread.Sleep()没有返回类型。它是同步的。在线程中,除了等待延迟完成之外,您实际上不能做任何事情。
至于在现实生活中的使用,我已经编程15年了。我从未在产品代码中使用过Thread.Sleep()。我找不到任何用例。 也许是因为我主要从事web应用程序开发。
如果当前线程被杀死,你使用thread。Sleep并且它正在执行,那么你可能会得到一个ThreadAbortException。 与任务。延迟您总是可以提供一个取消令牌并优雅地终止它。这就是我选择Task.Delay的原因之一。参见http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx
我也同意在这种情况下效率不是最重要的。
在异步程序中,两者的区别
await task.Delay()
//and
thread.sleep
在一个简单的应用程序中,一个可能更可取消,一个可能更准确,一个可能更快……但在一天结束的时候,两者都做同样的事情,他们阻塞正在执行的代码…
以下是调查结果:
1 00:00:00.0000767
Not Delayed.
1 00:00:00.2988809
Delayed 1 second.
4 00:00:01.3392148
Delayed 3 second.
5 00:00:03.3716776
Delayed 9 seconds.
5 00:00:09.3838139
Delayed 10 seconds
4 00:00:10.3411050
4 00:00:10.5313519
从这段代码:
var sw = new Stopwatch();
sw.Start();
Console.WriteLine($"{sw.Elapsed}");
var asyncTests = new AsyncTests();
var go1 = asyncTests.WriteWithSleep();
var go2 = asyncTests.WriteWithoutSleep();
await go1;
await go2;
sw.Stop();
Console.WriteLine($"{sw.Elapsed}");
Stopwatch sw1 = new Stopwatch();
Stopwatch sw = new Stopwatch();
public async Task WriteWithSleep()
{
sw.Start();
var delayedTask = Task.Delay(1000);
Console.WriteLine("Not Delayed.");
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} {sw.Elapsed}");
await delayedTask;
Console.WriteLine("Delayed 1 second.");
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} {sw.Elapsed}");
Thread.Sleep(9000);
Console.WriteLine("Delayed 10 seconds");
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} {sw.Elapsed}");
sw.Stop();
}
public async Task WriteWithoutSleep()
{
await Task.Delay(3000);
Console.WriteLine("Delayed 3 second.");
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} {sw.Elapsed}");
await Task.Delay(6000);
Console.WriteLine("Delayed 9 seconds.");
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} {sw.Elapsed}");
}
Sleep acts the same way as an immediate await, except it blocks the thread. A task that is assigned to a var may cause a thread switch when it is finally awaited. In this example, it looks like the code starts on thread 1, then creates thread 5 for WriteWithoutSleep(), but continues executing on thread 1 for ThreadWithSleep() until delayedTask is awaited. At that moment, thread 1's code flows into thread 4 and further execution in Main is now on thread 4; thread 1 is for lack of a better word thrown away.
以上所有的答案都很有价值。然而,在一个简单的控制台应用程序中,它似乎并不重要,除非在你使用的几次运行过程中,如果你立即等待你的Task.Delay()并且不打算使用取消令牌;
在一个复杂的应用程序中,让线程进入睡眠状态,还是因为创建任务而从一个线程跳到另一个线程,然后等待它们,还是立即等待,这是需要考虑的问题。
最后,放入Process.GetCurrentProcess(). threads。控制台应用程序(至少是我的)开头的Count在调试器模式下产生了13个线程。在等待调用之后,我在visual studio的调试器模式下有17个线程。我曾经读到consoleApp只有3个线程,其余的都是调试器线程,但是在没有调试的情况下运行consoleApp会导致8个线程和14个线程。在visual studio外部运行它的结果是8个线程和14个线程。
复制代码并粘贴它之后,线程数是相同的,8,14,所有内容都停留在线程4和5上。第二个线程。Sleep和task.delay不会导致线程跳转。所有这些研究都是为了提出:while线程。Sleep会阻塞一个线程,task.delay不会,并且有一个取消令牌,除非你的应用程序非常复杂,它真的不重要,因为表面上:task.delay和thread。睡眠也做着同样的事情。
任务之间最大的区别。延迟和线程。睡眠就是那个任务。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)。线程。睡眠仍然束缚着你的线程,任务。在等待的同时,延迟释放它以做其他工作。