Task.Delay().Wait() 发生了什么?

2024-01-01

我很困惑为什么Task.Delay().Wait() takes 4 倍多的时间, then Thread.Sleep()?

E.g. task-00正在运行仅线程 9并采取了2193ms? 我知道,同步等待在任务中很糟糕,因为整个线程被阻塞。它只是为了测试。

控制台应用程序中的简单测试:

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;

With Task.Delay().Wait():
任务 03 ThrID:05,等待 = 300 毫秒,启动:184 毫秒
任务 04 ThrID:07,等待 = 100 毫秒,开始:184 毫秒
任务 00 ThrID:09,等待 = 100 毫秒,开始:0 毫秒
任务 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 毫秒
任务 07 ThrID:10,等待 = 300 毫秒,结束:1189 毫秒
任务 08 ThrID:12,等待 = 100 毫秒,启动:226 毫秒
任务 09 ThrID:10,等待 = 300 毫秒,启动:226 毫秒
任务 09 ThrID:10,等待 = 300 毫秒,结束:2192 毫秒
任务 06 ThrID:04,等待 = 100 毫秒,结束:2193 毫秒
任务 08 ThrID:12,等待 = 100 毫秒,结束:2194 毫秒
任务 05 ThrID:03,等待 = 300 毫秒,结束:2193 毫秒
任务 03 ThrID:05,等待 = 300 毫秒,结束:2193 毫秒
任务 00 ThrID:09,等待 = 100 毫秒,结束:2193 毫秒
任务 02 ThrID:06,等待 = 100 毫秒,结束:2193 毫秒
任务 04 ThrID:07,等待 = 100 毫秒,结束:2193 毫秒
任务 01 ThrID:08,等待 = 300 毫秒,结束:2193 毫秒

With Thread.Sleep():
任务 00 ThrID:03,等待 = 100 毫秒,开始:0 毫秒
任务 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 毫秒
任务 00 ThrID:03,等待 = 100 毫秒,结束:284 毫秒
任务 08 ThrID:03,等待 = 100 毫秒,启动:184 毫秒
任务 02 ThrID:06,等待 = 100 毫秒,结束:285 毫秒
任务 09 ThrID:06,等待 = 300 毫秒,开始:184 毫秒
任务 04 ThrID:08,等待 = 100 毫秒,结束:286 毫秒
任务 06 ThrID:07,等待 = 100 毫秒,结束:293 毫秒
任务 08 ThrID:03,等待 = 100 毫秒,结束:385 毫秒
任务 03 ThrID:09,等待 = 300 毫秒,结束:485 毫秒
任务 05 ThrID:04,等待 = 300 毫秒,结束:486 毫秒
任务 01 ThrID:05,等待 = 300 毫秒,结束:493 毫秒
任务 07 ThrID:10,等待 = 300 毫秒,结束:494 毫秒
任务 09 ThrID:06,等待 = 300 毫秒,结束:586 毫秒

Edit:
With async拉姆达和await Task.Delay()Thread.Sleep(),也可能更快(511ms)。
Edit 2:
With ThreadPool.SetMinThreads(16, 16); Task.Delay().Wait()工作速度与Thread.Sleep循环中迭代 10 次。随着迭代次数的增加,速度又变慢了。同样有趣的是,如果不进行调整,我会增加迭代次数Thread.Sleep to 30,那么仍然更快10迭代与Task.Delay().Wait()
Edit 3:
超载Task.Delay(wait).Wait(wait)工作速度与Thread.Sleep()


我重写了发布的代码片段,以便更好地排序结果,我的全新笔记本电脑有太多内核,无法很好地解释现有的混乱输出。记录每个任务的开始和结束时间,并在完成后显示它们。并记录任务的实际开始时间。我有:

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 https://stackoverflow.com/questions/25907829/why-is-parallel-foreach-much-faster-then-asparallel-forall-even-though-msdn但除此之外,该用户的代码不会产生更灾难性的结果。原因几乎不可能看到,因为它隐藏在 .NETFramework 代码中,您必须查看 Task.Delay() 是如何实现的才能理解它。

相关代码is here https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,5896,注意它如何使用 System.Threading.Timer 来实现延迟。关于该计时器的一个重要细节是它的回调是在线程池上执行的。这是 Task.Delay() 实现“不使用不用付费”承诺的基本机制。

重要的细节是,如果线程池正忙于处理线程池执行请求,这可能需要一段时间。并不是计时器慢,问题是回调方法启动得不够快。这个程序中的问题是,Task.Run()添加了一堆请求,超过了可以同时执行的请求。发生死锁是因为由 Task.Run() 启动的 tp 线程在计时器回调执行之前无法完成 Wait() 调用。

通过将这段代码添加到 Main() 的开头,可以使其成为永久挂起程序的硬死锁:

     ThreadPool.SetMaxThreads(Environment.ProcessorCount, 1000);

但正常的最大线程要高得多。线程池管理器利用它来解决这种死锁。每秒一次,当现有线程未完成时,它允许比“理想”数量多两个线程执行。这就是您在输出中看到的内容。但一次只有两个,不足以对在 Wait() 调用上阻塞的 8 个繁忙线程产生太大影响。

Thread.Sleep() 调用没有这个问题,它不依赖于.NETFramework 代码或线程池来完成。操作系统线程调度程序负责处理它,并且它始终依靠时钟中断运行。因此,允许新的 tp 线程每 100 或 300 毫秒开始执行一次,而不是每秒一次。

很难给出具体建议来避免这种僵局陷阱。除了通用建议之外,始终避免工作线程阻塞。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Task.Delay().Wait() 发生了什么? 的相关文章

  • 如何将 SOLID 原则应用到现有项目中

    我对这个问题的主观性表示歉意 但我有点卡住了 我希望之前处理过这个问题的人能够提供一些指导和建议 我有 现在已经成为 一个用 C 2 0 编写的非常大的 RESTful API 项目 并且我的一些类已经变得巨大 我的主要 API 类就是一个
  • 如何将 .txt 文件中的数据转换为 xml? C#

    我在一个文本文件中有数千行数据 我想通过将其转换为更容易搜索的内容来轻松搜索 我希望 XML 或其他类型的大型数据结构 尽管我不确定它是否是最好的对于我的想法 每行的数据如下所示 第 31 册 托马斯 乔治 32 34 154 每本书都不是
  • cpp.react库的C++源代码中奇怪的“->* []”表达式

    这是我在文档中找到的 C 片段cpp react 库 https github com schlangster cpp react implicit parallelism auto in D MakeVar 0 auto op1 in g
  • 在 C# 中,如何根据在 gridview 行中单击的按钮引用特定产品记录

    我有一个显示产品网格视图的页面 该表内有一列 其中有一个名为 详细信息 的超链接 我想这样做 以便如果用户单击该特定产品的详细信息单元格 将打开一个新页面 提供有关该产品的更多信息 我不确定如何确定哪个Product记录链接的详细信息以及我
  • 如何使用 Regex.Replace 从字符串中删除数字?

    我需要使用Regex Replace从字符串中删除所有数字和符号 输入示例 123 abcd33输出示例 abcd 请尝试以下操作 var output Regex Replace input d string Empty The d标识符
  • 不同 C++ 文件中的相同类名

    如果两个 C 文件具有相同名称的类的不同定义 那么当它们被编译和链接时 即使没有警告也会抛出一些东西 例如 a cc class Student public std string foo return A void foo a Stude
  • 如何使用 x64 运行 cl?

    我遇到了和这里同样的问题致命错误 C1034 windows h 未设置包含路径 https stackoverflow com questions 931652 fatal error c1034 windows h no include
  • 从网页运行 ClickOnce 应用程序,无需用户操作

    我们有一个基于 Java 的 Web 应用程序以及用 C 编写的相同应用程序 如果 java 检查器发现客户端计算机上没有安装 Java 则应该运行该应用程序 这个想法是运行 C 单击一次 http en wikipedia org wik
  • 从 C# 使用 Odbc 调用 Oracle 包函数

    我在 Oracle 包中定义了一个函数 CREATE OR REPLACE PACKAGE BODY TESTUSER TESTPKG as FUNCTION testfunc n IN NUMBER RETURN NUMBER as be
  • 如果输入被重定向则执行操作

    我想知道如果我的输入被重定向 我应该如何在 C 程序中执行操作 例如 假设我有已编译的程序 prog 并且我将输入 input txt 重定向到它 我这样做 prog lt input txt 我如何在代码中检测到这一点 一般来说 您无法判
  • 在 C# 中为父窗体中的子窗体控件添加事件处理程序

    我有两种形式 一种是带有按钮和文本框的父表单 单击该按钮时 将打开一个对话框 该子窗体又包含一个文本框和一个按钮 现在我想要的是 每当子表单文本框中的文本更改时 父表单文本框中的文本会自动更改 为了获得这个 我所做的是 Form3 f3 n
  • 将 Word 转换为 PDF - 禁用“保存”对话框

    我有一个用 C 编写的 Word 到 PDF 转换器 除了一件事之外 它工作得很好 有时 在某些 Word 文件上 后台会出现一条消息保存源文件中的更改 gt 是 否 取消 但我没有对源文件进行任何更改 我只想从 Word 文件创建 PDF
  • C++ 对象用 new 创建,用 free() 销毁;这有多糟糕?

    我正在修改一个相对较大的 C 程序 不幸的是 并不总是清楚我之前的人使用的是 C 还是 C 语法 这是在一所大学的电气工程系 我们 EE 总是想用 C 来做所有事情 不幸的是 在这种情况下 人们实际上可以逃脱惩罚 但是 如果有人创建一个对象
  • 使动态创建的链接标签在 Winforms 中可点击

    我正在制作一个程序 允许用户单击由动态链接标签创建的公司名称 在我想知道如何做到这一点之前 我从未在 C 中使用过链接标签 可为特定用户生成的业务数量各不相同 因此每个用户的链接标签数量并不相同 然后我想捕获业务 ID 以进行 Json 调
  • 将 Lambda 表达式树与 IEnumerable 结合使用

    我一直在尝试了解有关使用 Lamba 表达式树的更多信息 因此我创建了一个简单的示例 这是代码 如果作为 C 程序粘贴到 LINQPad 中 它可以工作 void Main IEnumerable
  • 在 Win32 控制台应用程序中设置光标位置

    如何在 Win32 控制台应用程序中设置光标位置 最好 我想避免制作句柄并使用 Windows 控制台功能 我花了整个早上沿着那条黑暗的小巷跑 它产生的问题比它解决的问题还要多 我似乎记得当我在大学时使用 stdio 做这件事相对简单 但我
  • 没有“对 *this”功能的右值引用的解决方法

    我有一个围绕可移动对象的代理容器类 并希望代理能够隐式生成对底层对象的右值引用 但仅当代理本身被移动时 我相信我将能够按照提案 n2439 实施此行为 将移动语义扩展到 this http www open std org jtc1 sc2
  • 无法将字符串文字分配给装箱的 std::string 向量

    这是我的类型系统的简化版本 include
  • 为什么空循环使用如此多的处理器时间?

    如果我的代码中有一个空的 while 循环 例如 while true 它将把处理器的使用率提高到大约 25 但是 如果我执行以下操作 while true Sleep 1 它只会使用大约1 那么这是为什么呢 更新 感谢所有精彩的回复 但我
  • 当用户更改 Windows 中的语言键盘布局时如何通知?

    I want to show a message to user when the user changes the language keyboard layout of Windows for example from EN to FR

随机推荐

  • 在 C# 中获取属性值(反射)的最快方法

    我想知道从对象的属性获取值 仅针对此问题 的最快方法是什么 经过一番搜索后 我在这个网站上看到了 MarkGravell 的帖子 他写了这段代码 using System using System Reflection using Syst
  • new Integer(123)、Integer.valueOf(123) 和 just 123 之间的区别

    最近我看到这样的代码 Java myMethod new Integer 123 我目前正在重构一些代码 声纳工具中有一个提示 使用这样的东西对内存更友好 myMethod Integer valueOf 123 但是在这种情况下 我认为使
  • 来自主线程的 VTK 窗口线程,C++

    我刚刚学习 VTK 和 C GUI 编程 希望有一个简单的问题 主应用程序在应用程序中的某个时刻启动渲染的窗口 希望在显示 VTK 窗口时主线程能够继续 是否有特定的方法可以将 VTK 窗口作为线程启动 我的环境是 Linux 可以使用 b
  • IFNDR 是否优先于可诊断的违规行为?

    简介 合规性 一般 2 https timsong cpp github io cppwp n4868 intro compliance general 2指定编译器应如何处理给定的程序 特别是它有两点涉及格式错误的程序 2 2 要求编译器
  • Numpy 重新索引前 N 个自然数

    我有一个索引非常稀疏的矩阵 行和列中的最大值都超过 130000 但其中只有少数行 列实际上具有非零值 因此 我希望通过前 N 个自然数将行索引和列索引移动为仅表示非零索引 从视觉上看 我想要一个像这样的示例矩阵 1 0 1 0 0 0 0
  • 在circos中使用circos函数

    有人能帮我吗 如何在数据中添加 circos 函数 当我尝试时 我收到一条错误消息 但它不会产生任何结果 我想做一个像 1 号表示一样的甜甜圈图形 但我还有另一个结果 我们可以在另一张图片中看到 试图跟随本指南 https jokergoo
  • JNI4Net C# 到 Java

    我有一个简单的 Java 类 名为jniBridge Calculator有一种简单的方法Add int a int b 使用 eclipse 构建项目后 我将项目导出为 JAR 文件 然后我在 JAR 文件上调用 proxygen 这会生
  • Ruby 的 File.open 给出“没有这样的文件或目录 - text.txt (Errno::ENOENT)”错误

    我在我的 Win 7 机器上安装了 Ruby 1 9 2 创建了一个简单的analyzer rb文件 它有这一行 File open text txt each line puts line 当我运行代码时 它给我这个错误 analyzer
  • 如何将 .net 程序集标记为安全?

    如何将程序集标记为 安全 或者 当程序集中的某些内容不 安全 时 我如何让 Visual Studio 告诉我 有时 除非程序集 安全 否则您不能使用它 例如从 SQL Server https stackoverflow com ques
  • C++ 获取类的所有对象

    C 中有没有一种方法可以获取一个类的所有对象 就像在 Python 中一样 我们可以这样做 class name objects all 获取一个类的所有对象 如果存在的话 它在 C 中的类似物是什么 您可以自己执行此操作 但请确保您知道自
  • RxJava - Just 与 From

    使用时我得到相同的输出Observable just vs Observable from在以下情况下 public void myfunc swap out just for from here and i get the same re
  • 更改函数内部的指针不会反映在函数外部[重复]

    这个问题在这里已经有答案了 void alloco int ppa int i printf inside alloco d n ppa ppa int malloc 20 ppa 15 9 printf size of a d n siz
  • NetworkSecurityConfig:未指定网络安全配置 - Android 7.0 错误?

    我在 android 7 0 0 上遇到一些问题 我在我的应用程序中使用 volley 库 除了 Android 7 0 之外 它运行良好 这是我的代码的一部分 String url goster http 185 126 217 71 c
  • 具有相同方法名称的两个接口 - 方法的实现[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 假设我有两个接口 interface IOne public void method and interface ITwo public voi
  • C++ 全局常量问题

    我们在一系列文件中定义了这些 实用 常量集 问题源于这样一个事实 太多文件包含这些全局常量文件 如果我们向其中一个文件添加常量并尝试构建 它会构建整个库 这需要一个多小时的时间 有人能为这种方法提出更好的方法吗 我们将不胜感激 首先 如果您
  • 查找数组中是否包含 2 旁边的 2

    我被这个问题困住了 给定一个整数数组 如果该数组某处的 2 旁边包含 2 则返回 True has22 1 2 2 True has22 1 2 1 2 False has22 2 1 2 False 我知道基本思想 存在语法错误 但我无法
  • Python TypeError:不支持的操作数类型 -:“float”和“NoneType”

    有谁知道为什么我会收到这样的错误 TypeError unsupported operand type s for float and NoneType 如果你这样做 我将非常感激 我对此很陌生 正在努力学习 但我真的陷入了 Python
  • 将模型传递给局部视图

    我有一个 Address 部分视图 该部分视图包含与地址模型匹配的所有地址字段 在此视图的顶部 我将模型设置如下 模型数据 地址 在我的 CustomerInfo 视图中 我尝试以下操作将地址字段呈现为表单的一部分 Html Partial
  • git - 默认推送到 --recurse-submodules=check

    我总是忘记推送子模块 有时我忘记添加 recurse submodules check to git push 更糟糕的是 我团队中的其他人可能也会这样做 有没有git config我们可以设置的选项check默认值 Git v2 7 0
  • Task.Delay().Wait() 发生了什么?

    我很困惑为什么Task Delay Wait takes 4 倍多的时间 then Thread Sleep E g task 00正在运行仅线程 9并采取了2193ms 我知道 同步等待在任务中很糟糕 因为整个线程被阻塞 它只是为了测试