等待任务.Delay(foo);需要几秒而不是毫秒

2023-12-25

使用可变延迟Task.Delay当与类似 IO 的操作结合时,随机花费几秒而不是几毫秒。

重现代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication {
    class Program {
        static void Main(string[] args) {

            Task[] wait = {
                              new delayTest().looper(5250, 20), 
                              new delayTest().looper(3500, 30),
                              new delayTest().looper(2625, 40), 
                              new delayTest().looper(2100, 50)
                          };
            Task.WaitAll(wait);

            Console.WriteLine("All Done");
            Console.ReadLine();
        }
    }
    class delayTest {
        private Stopwatch sw = new Stopwatch();

        public delayTest() {
            sw.Start();
        }

        public async Task looper(int count, int delay) {
            var start = sw.Elapsed;
            Console.WriteLine("Start ({0}, {1})", count, delay);
            for (int i = 0; i < count; i++) {
                var before = sw.Elapsed;
                var totalDelay = TimeSpan.FromMilliseconds(i * delay) + start;
                double wait = (totalDelay - sw.Elapsed).TotalMilliseconds;
                if (wait > 0) {
                    await Task.Delay((int)wait);
                    SpinWait.SpinUntil(() => false, 1);
                }
                var finalDelay = (sw.Elapsed - before).TotalMilliseconds;
                if (finalDelay > 30 + delay) {
                    Console.WriteLine("Slow ({0}, {1}): {4} Expected {2:0.0}ms got {3:0.0}ms", count, delay, wait, finalDelay, i);
                }
            }
            Console.WriteLine("Done ({0}, {1})", count, delay);
        }
    }
}

也对此进行了报道connect https://github.com/Dorus/taskDelayProblem.


为了完整起见,将老问题留在下面。

我正在运行一个从网络流读取的任务,然后延迟 20 毫秒,然后再次读取(执行 500 次读取,这应该需要大约 10 秒)。当我只读取 1 个任务时,这种方法效果很好,但当我运行多个任务时,会发生奇怪的事情,其中​​一些任务有很长(60 秒)的延迟。我的 ms-delay 任务突然中途挂起。

我正在运行以下命令code https://github.com/Dorus/taskDelayProblem(简化):

var sw = Stopwatch();
sw.Start()
await Task.Delay(20); // actually delay is 10, 20, 30 or 40;
if (sw.Elapsed.TotalSeconds > 1) {
    Console.WriteLine("Sleep: {0:0.00}s", sw.Elapsed.TotalSeconds);
}

这打印:

睡眠:11.87秒

(实际上,99% 的情况下它会产生 20 毫秒的延迟,这些延迟会被忽略)。

这一延迟几乎比预期长了 600 倍。同样的延迟同时发生在 3 个独立的线程上,并且它们也同时再次继续。

60 秒睡眠任务会在短任务完成后约 40 秒正常唤醒。

有一半的时间这个问题甚至不会发生。另一半,它有 11.5-12 秒的一致延迟。我怀疑是调度或线程池问题,但所有线程都应该是空闲的。

当我在卡住阶段暂停程序时,主线程堆栈跟踪保持不变Task.WaitAll, 3 个任务安排在await Task.Delay(20)并且计划了一项任务await Task.Delay(60000)。还有另外 4 个任务正在等待前 4 个任务,报告类似“任务 24”正在等待此对象:“任务 5313”(由线程 0 拥有)”。所有 4 个任务都表示等待任务由线程 0 拥有。还有 4 个ContinueWith 任务我认为我可以忽略。

还有一些其他事情正在发生,例如第二个控制台应用程序写入网络流,但一个控制台应用程序不应影响另一个控制台应用程序。

我对此完全一无所知。到底是怎么回事?

Update:

根据评论和问题:

当我运行程序 4 次时,2-3 次它将挂起 10-15 秒,1-2 次它将正常运行(并且不会打印“Sleep: {0:0.00}s”。)

Thread.Count确实会上升,但无论挂起,这种情况都会发生。我刚刚跑了一次,它没有挂起,并且Thread.Count从24开始,1秒后上升到40,22秒左右短任务正常完成,然后Thread.Count在接下来的 40 秒内缓慢降至 22。

更多代码,完整代码可以在下面的链接中找到。启动客户端:

List<Task> tasks = new List<Task>();

private void makeClient(int delay, int startDelay) {
    Task task = new ClientConnection(this, delay, startDelay).connectAsync();
    task.ContinueWith(_ => {
        lock (tasks) { tasks.Remove(task); }
    });
    lock (tasks) { tasks.Add(task); }
}

private void start() {
    DateTime start = DateTime.Now;
    Console.WriteLine("Starting clients...");

    int[] iList = new[]  { 
        0,1,1,2,
        10, 20, 30, 40};
    foreach (int delay in iList) {
        makeClient(delay, 0); ;
    }
    makeClient(15, 40);
    Console.WriteLine("Done making");

    tasks.Add(displayThreads());

    waitForTasks(tasks);
    Console.WriteLine("All done.");
}

private static void waitForTasks(List<Task> tasks) {
    Task[] waitFor;
    lock (tasks) {
        waitFor = tasks.ToArray();
    }
    Task.WaitAll(waitFor);
}

另外,我尝试更换Delay(20) with await Task.Run(() => Thread.Sleep(20)) Thread.Count现在从 29 到 43,然后又回到 24,但是在多个符文中它永远不会挂起。

有还是没有ThreadPool.SetMinThreads(500, 500), using TaskExt.Delay通过 诺塞拉蒂 https://gist.github.com/noserati/bf9432246cb9f0122c00它不会挂起。 (也就是说,即使切换 1 行代码有时也会阻止它挂起,只有在我重新启动项目 4 次后才会随机继续,但我现在已经连续尝试了 6 次,没有任何问题)。

我已经尝试过上面的所有内容,有或没有ThreadPool.SetMinThreads到目前为止,没有任何区别。

更新2:CODE! https://github.com/Dorus/taskDelayProblem


在没有看到更多代码的情况下,很难做出进一步的猜测,但我想总结一下这些评论,它可能会在将来帮助其他人:

  • 我们已经知道了the ThreadPool口吃 http://joeduffyblog.com/2006/07/08/clr-thread-pool-injection-stuttering-problems/这里不是问题,因为ThreadPool.SetMinThreads(500, 500)没有帮助。

  • 有没有SynchronizationContext位于任务工作流程中的任何位置吗?地方Debug.Assert(SyncrhonizationContext.Current == null)到处去检查一下。使用ConfigureAwait(false)与每一个await.

  • 有没有.Wait, .WaitOne, .WaitAll, WaitAny, .Result在代码中的任何地方使用?任何lock () { ... }结构体?Monitor.Enter/Exit或任何其他阻塞同步原语?

  • 关于这一点:我已经更换了Task.Delay(20) with Task.Yield(); Thread.Sleep(20)作为一种解决方法,这是可行的。但是,是的,我继续尝试弄清楚这里发生了什么,因为 Task.Delay(20) 可以如此超出范围的想法使其完全无法使用。

    这听起来确实令人担忧。出现错误的可能性非常小Task.Delay,但一切皆有可能。为了进行实验,尝试替换await Task.Delay(20) with await Task.Run(() => Thread.Sleep(20)),有ThreadPool.SetMinThreads(500, 500)仍然在原地。

    我也有一个实验性的实现Delay它使用非托管CreateTimerQueueTimer https://msdn.microsoft.com/en-us/library/windows/desktop/ms682485%28v=vs.85%29.aspxAPI(不同于Task.Delay,它使用System.Threading.Timer,这又使用托管TimerQueue)。可用这里作为要点 https://gist.github.com/noserati/bf9432246cb9f0122c00。请随意尝试一下TaskExt.Delay而不是标准Task.Delay。计时器回调被发布到ThreadPool, so ThreadPool.SetMinThreads(500, 500)仍然应该用于这个实验。我怀疑这会产生任何影响,但我很想知道。

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

等待任务.Delay(foo);需要几秒而不是毫秒 的相关文章

  • 在 Xamarin Android 中将图像从 URL 异步加载到 ImageView 中

    我有一个包含多个项目的 ListView 列表中的每个项目都应该有一个与之关联的图像 我创建了一个数组适配器来保存每个列表项并具有我希望加载的图像的 url 我正在尝试使用 Web 请求异步加载图像 并设置图像并在加载后在视图中更新它 但视
  • 如何在没有 Control.Invoke() 的情况下从后台线程修改控件属性

    最近 我们遇到了一些旧版 WinForms 应用程序 我们需要更新一些新功能 在专家测试该应用程序时 发现一些旧功能被破坏 无效的跨线程操作 现在 在您认为我是新手之前 我确实有一些 Windows 窗体应用程序的经验 我不是专家 但我认为
  • FFMPEG Seeking 带来音频伪影

    我正在使用 ffmpeg 实现音频解码器 在读取音频甚至搜索已经可以工作时 我无法找到一种在搜索后清除缓冲区的方法 因此当应用程序在搜索后立即开始读取音频时 我没有任何工件 avcodec flush buffers似乎对内部缓冲区没有任何
  • 使用 Microsoft Graph API 订阅 Outlook 推送通知时出现 400 错误请求错误

    我正在尝试使用 Microsoft Graph API 创建订阅以通过推送通知获取 Outlook 电子邮件 mentions 我在用本文档 https learn microsoft com en us graph api subscri
  • 如何在我的应用程序中使用 Windows Key

    Like Windows Key E Opens a new Explorer Window And Windows Key R Displays the Run command 如何在应用程序的 KeyDown 事件中使用 Windows
  • 使用 Google Analytics API 在 C# 中显示信息

    我一整天都在寻找一个好的解决方案 但谷歌发展得太快了 我找不到有效的解决方案 我想做的是 我有一个 Web 应用程序 它有一个管理部分 用户需要登录才能查看信息 在本节中 我想显示来自 GA 的一些数据 例如某些特定网址的综合浏览量 因为我
  • c 中的错误:声明隐藏了全局范围内的变量

    当我尝试编译以下代码时 我收到此错误消息 错误 声明隐藏了全局范围内的变量 无效迭代器 节点 根 我不明白我到底在哪里隐藏或隐藏了之前声明的全局变量 我怎样才能解决这个问题 typedef node typedef struct node
  • 为什么模板不能位于外部“C”块内?

    这是一个后续问题一个答案 https stackoverflow com questions 4866433 is it possible to typedef a pointer to extern c function type wit
  • 使用向量的 merge_sort 在少于 9 个输入的情况下效果很好

    不知何故 我使用向量实现了合并排序 问题是 它可以在少于 9 个输入的情况下正常工作 但在有 9 个或更多输入的情况下 它会执行一些我不明白的操作 如下所示 Input 5 4 3 2 1 6 5 4 3 2 1 9 8 7 6 5 4 3
  • 如何在 Team Foundation 上强制发表有意义的签入评论?

    我有一个开发团队有一个坏习惯 他们写道poor签入评论 当我们必须在团队基础上查看文件的历史记录时 这使得它成为一场噩梦 我已经启用了变更集评论政策 这样他们甚至可以在签到时留下评论 否则他们不会 我们就团队的工作质量进行了一些讨论 他们很
  • 线程、进程和 Application.Exit()

    我的应用程序由主消息循环 GUI 和线程 Task Factory 组成 在线程中我调用一些第三方应用程序var p new Process 但是当我调用Application Exit 在消息循环中 我可以看到在线程中启动的进程仍在内存中
  • *.tlb 文件在运行时使用过吗?

    我正在开发一个通过 COM 互操作公开一些 NET API 的产品 作为构建的一部分 我们为所有此类程序集生成 tlb 文件 并将它们作为单独 SDK 包的一部分提供 我们的客户可以在我们的产品之上安装 SDK 并创建使用我们的 COM A
  • 像“1$”这样的位置参数如何与 printf() 一起使用?

    By man I find printf d width num and printf 2 1 d width num 是等价的 但在我看来 第二种风格应该与以下相同 printf d num width 然而通过测试似乎man是对的 为什
  • .NET 选项将视频文件流式传输为网络摄像头图像

    我有兴趣开发一个应用程序 它允许我从 xml 构建视频列表 包含视频标题 持续时间等 并将该列表作为我的网络摄像头流播放 这意味着 如果我要访问 ustream tv 或在实时通讯软件上激活我的网络摄像头 我的视频播放列表将注册为我的活动网
  • AccessViolationException 未处理

    我正在尝试使用史蒂夫 桑德森的博客文章 http blog stevensanderson com 2010 01 28 editing a variable length list aspnet mvc 2 style 为了在我的 ASP
  • EPPlus Excel 更改单元格颜色

    我正在尝试将给定单元格的颜色设置为另一个单元格的颜色 该单元格已在模板中着色 但worksheet Cells row col Style Fill BackgroundColor似乎没有get财产 是否可以做到这一点 或者我是否必须在互联
  • 已过时 - OpenCV 的错误模式

    我正在使用 OpenCV 1 进行一些图像处理 并且对 cvSetErrMode 函数 它是 CxCore 的一部分 感到困惑 OpenCV 具有三种错误模式 叶 调用错误处理程序后 程序终止 Parent 程序没有终止 但错误处理程序被调
  • 如何构建印度尼西亚电话号码正则表达式

    这些是一些印度尼西亚的电话号码 08xxxxxxxxx 至少包含 11 个字符长度 08xxxxxxxxxxx 始终以 08 开头 我发现这个很有用 Regex regex new Regex 08 0 9 0 9 0 9 0 9 0 9
  • Bing 地图运行时错误 Windows 8.1

    当我运行带有 Bing Map 集成的 Windows 8 1 应用程序时 出现以下错误 Windows UI Xaml Markup XamlParseException 类型的异常 发生在 DistanceApp exe 中 但未在用户
  • 将 viewbag 从操作控制器传递到部分视图

    我有一个带有部分视图的 mvc 视图 控制器中有一个 ActionResult 方法 它将返回 PartialView 因此 我需要将 ViewBag 数据从 ActionResult 方法传递到 Partial View 这是我的控制器

随机推荐

  • 仅获取正在使用的 CDI 托管 Bean

    我的目标是从 JSF2 ExceptionHandlerWrapper 中获取所有正在服务的 CDI 托管 bean 某个父类的 的集合 请注意 异常处理程序部分很重要 因为该类本身不是有效的注入目标 所以我的假设 也许不正确 是我唯一的途
  • C++调用模板类的特定模板构造函数

    如果类也是模板 是否可以使用模板参数调用构造函数 include
  • 如何使来电静音

    我正在尝试将来电静音并防止 BlackBerry 设备响铃 我尝试了 Alert setVolume 0 和一些 EventInjector 键 但这不起作用 那么如何让来电静音呢 我对你的问题感到困惑 并决定接受挑战 我尝试了不同的事情
  • elisp:将文件读入列表列表

    我需要将文件内容读入二维列表 由换行符和空格分隔 例如 a b c d 需要成为 list list a b list c d 目前我只知道如何将内容读入由换行符确定的简单列表中 每当我需要使用该列表中的元素时 我每次都必须用空格将其拆分
  • 从构造函数初始化 Typescript 类值

    我使用 TypeScript 通过 KnockoutJS 创建一些类 并从 WebAPI 返回的一些 JSON 加载数据 问题是我想从构造函数将 JSON 值复制到我的 TypeScript 类中 但如果我仅在基类中执行此操作 则继承的属性
  • JSON.net 不包含 EmitDefaultValue false 的 null 属性

    我有一个包含许多数据合约的系统 其中成员装饰有 DataMember EmitDefaultValue false 我有一个情况 当序列化为 JSON 时 我需要在 null 时包含成员 无论我选择什么序列化器设置 我都无法使其工作 Tes
  • 在 GTK+3 中滚动 WebKit2.Webkit 窗口

    如何滚动webkit2gtk widget In webkitgtk aka webkit1 你包裹你的WebView in a ScrolledWindow 因此可以使用其vadjustment财产 For wekit2gtk 这个调用W
  • 将 CMS 与现有 ASP.NET 网站集成

    我正在尝试将 CMS 集成到使用 ASP NET 构建的现有网站中 aspx文件和 aspx cs文件背后的代码 未编译 我的研究表明 我的最佳候选者是 N2 CMS 我理想的方法是使用各种可编辑内容类型配置编辑器 并让我现有的页面和用户控
  • 如何正确使用 Django 中的“choices”字段选项

    我正在这里阅读教程 https docs djangoproject com en 1 5 ref models fields choices https docs djangoproject com en 1 5 ref models f
  • gpuDevice() 工具包版本始终为 5.5

    无论我如何重新安装CUDA驱动程序和工具包 当输入gpuDevice 时 它总是显示 CUDADevice with properties Name Quadro K2000M Index 1 ComputeCapability 3 0 S
  • 删除/清空的 Graphite Whisper 文件自动重新生成

    我试图删除一些旧的石墨测试耳语指标 但没有成功 我可以通过删除文件来删除指标 看 如何清理石墨耳语的数据 https stackoverflow com questions 9587161 how to cleanup the graphi
  • 如何使用 Gitlab 设置代码审查?

    如何使用 Gitlab 设置代码审查 我看到它在 Gitlab 网站上被列为一项功能 但我似乎找不到有关如何设置该功能的说明 就这一点而言 任何指向 Gitlab 用户手册的链接将不胜感激 我的一些搜索表明 合并请求 是可行的方法 但我发现
  • 从命令行启动 AVD 时卡在“撤销 Google 应用程序的麦克风权限”上

    我正在运行命令来启动 AVD 但是 当设备启动时 卡在这个错误上 撤销 Google 应用的麦克风权限 有什么线索吗 我正在使用 AVD 设备 API 28 运行这些命令时出现同样的错误 Users username Library And
  • 了解 WCF

    谁能给我指出一个用图片和简单代码片段解释 WCF 的资源 我厌倦了在所有搜索结果中进行谷歌搜索并找到相同的 ABC 文章 WCF 是一项非常复杂的技术 在我看来 它的文档记录非常少 它的启动和运行非常容易 但是运行大型应用程序的性能调整可能
  • 如何使用 dalli 和 Rails 将内存缓存板大小增加到 1MB 以上?

    我正在使用 Ruby on Rails 和 dalli gem 通过 memcache 进行缓存 默认值 键值存储中的值 又名slab 最大大小为1MB 我想将其增加到 2MB dalli 的文档 https stackoverflow c
  • 无法找到名为“entityManagerFactory”的 bean

    我的应用程序无法启动 它由 Spring Boot JPA SQLite 组成 但 Spring Boot 和 MySQL 运行良好 我不明白为什么会发生这种情况 错误是 无法找到名为 entityManagerFactory 的 bean
  • Stripe 在 Python 中不会抛出充电错误

    我正在使用 Python 中的 stripe 库进行信用卡收费 我使用 customerID 来收费 而不是使用令牌 因为我想重复使用该卡 而无需每次都询问 成功过程运行得很好 但是 如果我创建错误条件 则永远不会抛出 例外 我正在使用无效
  • Javascript document.cookie 总是返回空字符串

    我在客户端 javascript 设置 cookie 时遇到了这个真正奇怪的问题 我目前正在开发一个小型的 1 页演示 以使用 cookie 来存储一些 首选项 请注意 我无法在此演示中使用服务器端语言或任何第 3 方 jQuery 插件
  • 尝试使用 python 3 加载 JSON 对象时出错

    我有以下 json 对象 我试图用 python 3 解析 customerData Joe visits 1 Carol visits 2 Howard visits 3 Carrie visits 4 我使用以下 python 代码来解
  • 等待任务.Delay(foo);需要几秒而不是毫秒

    使用可变延迟Task Delay当与类似 IO 的操作结合时 随机花费几秒而不是几毫秒 重现代码 using System using System Collections Generic using System Diagnostics