- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我很困惑,为什么 Task.Delay().Wait()
需要 4 倍的时间,然后是 Thread.Sleep()
?
例如task-00 是否在仅线程 9 上运行并花费了 2193 毫秒?我知道,同步等待在任务中很糟糕,因为整个线程都被阻塞了。仅供测试。
控制台应用程序中的简单测试:
bool flag = true;
var sw = Stopwatch.StartNew();
for (int i = 0; i < 10; i++)
{
var cntr = i;
{
var start = sw.ElapsedMilliseconds;
var wait = flag ? 100 : 300;
flag = !flag;
Task.Run(() =>
{
Console.WriteLine($"task-{cntr.ToString("00")} \t ThrID: {Thread.CurrentThread.ManagedThreadId.ToString("00")},\t Wait={wait}ms, \t START: {start}ms");
//Thread.Sleep(wait);
Task.Delay(wait).Wait();
Console.WriteLine($"task-{cntr.ToString("00")} \t ThrID: {Thread.CurrentThread.ManagedThreadId.ToString("00")},\t Wait={wait}ms, \t END: {sw.ElapsedMilliseconds}ms");
;
});
}
}
Console.ReadKey();
return;
使用Task.Delay().Wait()
:
任务 03 ThrID:05,等待 = 300 毫秒,开始:184 毫秒
任务 04 ThrID:07,等待 = 100 毫秒,开始:184 毫秒
task-00 ThrID: 09, Wait=100ms, START: 0ms
任务 06 ThrID:04,等待 = 100 毫秒,开始:185 毫秒
任务 01 ThrID:08,等待 = 300 毫秒,开始:183 毫秒
任务 05 ThrID:03,等待 = 300 毫秒,开始:185 毫秒
任务 02 ThrID:06,等待 = 100 毫秒,开始:184 毫秒
任务 07 ThrID:10,等待 = 300 毫秒,开始:209 毫秒
task-07 ThrID: 10, Wait=300ms, END: 1189ms
task-08 ThrID: 12, Wait=100ms, START: 226ms
task-09 ThrID: 10, Wait=300ms, START: 226ms
task-09 ThrID: 10, Wait=300ms, END: 2192ms
task-06 ThrID: 04, Wait=100ms, END: 2193ms
task-08 ThrID: 12, Wait=100ms, END: 2194ms
任务 05 ThrID:03,等待 = 300 毫秒,结束:2193 毫秒
task-03 ThrID: 05, Wait=300ms, END: 2193ms
task-00 ThrID: 09, Wait=100ms, END: 2193ms
task-02 ThrID: 06, Wait=100ms, END: 2193ms
task-04 ThrID: 07, Wait=100ms, END: 2193ms
task-01 ThrID: 08, Wait=300ms, END: 2193ms
使用Thread.Sleep()
:
task-00 ThrID: 03, Wait=100ms, START: 0ms
任务 03 ThrID:09,等待 = 300 毫秒,开始:179 毫秒
任务 02 ThrID:06,等待 = 100 毫秒,开始:178 毫秒
任务 04 ThrID:08,等待 = 100 毫秒,开始:179 毫秒
任务 05 ThrID:04,等待 = 300 毫秒,开始:179 毫秒
任务 06 ThrID:07,等待 = 100 毫秒,开始:184 毫秒
任务 01 ThrID:05,等待 = 300 毫秒,开始:178 毫秒
任务 07 ThrID:10,等待 = 300 毫秒,开始:184 毫秒
task-00 ThrID: 03, Wait=100ms, END: 284ms
任务 08 ThrID:03,等待 = 100 毫秒,开始:184 毫秒
task-02 ThrID: 06, Wait=100ms, END: 285ms
任务 09 ThrID:06,等待 = 300 毫秒,开始:184 毫秒
task-04 ThrID: 08, Wait=100ms, END: 286ms
task-06 ThrID: 07, Wait=100ms, END: 293ms
task-08 ThrID: 03, Wait=100ms, END: 385ms
task-03 ThrID: 09, Wait=300ms, END: 485ms
task-05 ThrID: 04, Wait=300ms, END: 486ms
任务 01 ThrID:05,等待 = 300 毫秒,结束:493 毫秒
task-07 ThrID: 10, Wait=300ms, END: 494ms
task-09 ThrID: 06, Wait=300ms, END: 586ms
编辑:
使用 async
lambda 和 await
Task.Delay()
与 Thread.Sleep()
一样快,可能是也更快(511 毫秒)。
编辑 2:
使用 ThreadPool.SetMinThreads(16, 16);
Task.Delay().Wait()
与 Thread.Sleep
一样快 10 次迭代在循环。随着更多的迭代,它又变慢了。这也很有趣,如果不调整我将 Thread.Sleep
的迭代次数增加到 30,它仍然更快,然后 10 迭代Task.Delay().Wait()
编辑 3:
重载 Task.Delay(wait).Wait(wait)
的工作速度与 Thread.Sleep()
最佳答案
我稍微重写了发布的代码片段,以便更好地排序结果,我全新的笔记本电脑有太多内核,无法很好地解释现有的困惑输出。记录每项任务的开始和结束时间,并在全部完成后显示。并记录Task的实际开始时间。我得到了:
0: 68 - 5031
1: 69 - 5031
2: 68 - 5031
3: 69 - 5031
4: 69 - 1032
5: 68 - 5031
6: 68 - 5031
7: 69 - 5031
8: 1033 - 5031
9: 1033 - 2032
10: 2032 - 5031
11: 2032 - 3030
12: 3030 - 5031
13: 3030 - 4029
14: 4030 - 5031
15: 4030 - 5031
啊,这突然变得很有意义了。处理线程池线程时要始终注意的模式。请注意,每秒钟都会发生一些重要的事情,两个 tp 线程开始运行,其中一些可以完成。
这是一个死锁场景,类似于this Q+A但除此之外,该用户的代码不会造成更灾难性的后果。原因几乎是不可能的,因为它隐藏在 .NETFramework 代码中,您必须查看 Task.Delay() 的实现方式才能理解它。
相关代码is here ,请注意它如何使用 System.Threading.Timer 来实现延迟。关于该计时器的一个重要细节是它的回调是在线程池上执行的。这是 Task.Delay() 可以实现“你不用为你不用的东西付费” promise 的基 native 制。
具体细节是,如果线程池正忙于处理线程池执行请求,这可能需要一段时间。不是计时器慢,问题是回调方法启动不够快。这个程序中的问题,Task.Run() 增加了一堆请求,超过了可以同时执行的请求。死锁的发生是因为由 Task.Run() 启动的 tp 线程在计时器回调执行之前无法完成 Wait() 调用。
您可以通过将这段代码添加到 Main() 的开头来使其成为一个使程序永远挂起的硬死锁:
ThreadPool.SetMaxThreads(Environment.ProcessorCount, 1000);
但正常的最大线程要高得多。线程池管理器利用它来解决这种死锁。当现有线程未完成时,它每秒允许执行比“理想”数量多两个线程。这就是您在输出中看到的内容。但它一次只有两个,不足以对 Wait() 调用中阻塞的 8 个繁忙线程造成太大影响。
Thread.Sleep() 调用没有这个问题,它不依赖于.NETFramework 代码或线程池来完成。它是 OS 线程调度程序来处理它,并且它始终依靠时钟中断运行。因此允许新的 tp 线程每 100 或 300 毫秒开始执行一次,而不是每秒一次。
很难给出避免这种死锁陷阱的具体建议。除了通用建议外,始终避免阻塞工作线程。
关于c# - Task.Delay().Wait() 是怎么回事?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53648014/
我是一名优秀的程序员,十分优秀!