【问题标题】:Task.Factory.StartNew starts with a great delay despite having available threads in threadpool尽管线程池中有可用线程,Task.Factory.StartNew 的启动延迟很大
【发布时间】:2018-12-03 08:15:34
【问题描述】:

这个问题是我上一个问题的延续:

It takes more than a few seconds for a task to start running

我现在知道如何准确地重现这种情况。 Task.Factory.StartNew 被安排在线程池中,所以我正在记录以下内容(就在我调用 Factory.StartNew 之前):

        int workerThreads = 0;
        int completionPortThreads = 0;
        ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
        ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
        var tokenSource = new CancellationTokenSource();
        CancellationToken token = tokenSource.Token;
         //I HAVE A LOG HERE

        Task task = Task.Factory.StartNew(() =>
        {
          //I HAVE A LOG ALSO HERE, AND THAT'S HOW I KNOW,    
          //THE TASK INVOCATION IS DELAYED, AND THE DALAY IS NOT DUE TO MY CODE WITHIN THE TASK
           // Some action that returns a boolean - **CODE_A**
        }).ContinueWith((task2) =>
        {
            result= task2.Result;
            if (!result)
            {
                //Another action **CODE_B**
            }
        }, token);

当 bug 重现时,我得到 32767 作为 Max 工作线程,32756 作为可用工作线程。

现在,有些东西我不明白。 至少据我了解,一旦线程池达到过载,线程池将立即停止创建新线程。这可能是我的任务延迟的原因(从调用 Factory.StartNew 开始超过 5 秒后开始)。

但是当延迟发生时,我看到我的线程池中有 32756 个可用的工作线程,那么为什么线程池不使用这 32756 个可用的工作线程之一来立即启动我的任务?

可用线程在 ThreadPool 上(我的意思是,我调用 ThreadPool.GetAvailableThreads),Task.Factory.StartNew 从 threadPool 分配一个任务。那么,尽管线程池中有可用线程,为什么我会出现这种延迟?

【问题讨论】:

  • 你的代码是做什么的,为什么你认为是 StartNew 慢而不是说,代码本身?您是否尝试过分析代码?只需在调试期间暂停并检查Parallel Stacks 窗口。它显示了什么?你是在要求人们猜测。可以肯定的是,线程池并不慢,除非您用任务淹没 CPU,将所有可用时间浪费在线程切换上。毕竟,你不能同时运行的线程数超过逻辑核心数
  • @Panagiotis Kanavos 我肯定知道,因为我在调用 StartNew 之前和开始时有一个日志,甚至在我的代码运行之前(任务中的代码)。跨度>
  • @DimaK 所以你根本不知道。你在假设。我们甚至不能这样做,因为您还没有发布任何内容。 无法知道这是代码的错,因为你没有检查还有多少其他任务。发布您的代码,或使用并行调试窗口检查延迟发生时发生的情况。
  • 这不是您需要查看的 MAX 工作线程值 - 这是您通过 ThreadPool.GetMinThreads() 获得的 MIN 值。最大值是可以活动的绝对最大线程数。最小值是始终保持活动状态的数字。如果您尝试在活动线程数小于最大值(且大于最小值)时启动线程,您将看到 2 秒延迟。

标签: c# multithreading task


【解决方案1】:

这不是您需要查看的 MAX 工作线程值 - 这是您通过 ThreadPool.GetMinThreads() 获得的 MIN 值。

最大值是可以活动的绝对最大线程数。最小值是始终保持活动状态的数字。如果您尝试在活动线程数小于最大值(且大于最小值)时启动线程,您将看到 2 秒延迟。

如果绝对必要(在某些情况下是这样),您可以更改最小线程数,但一般来说,如果您发现自己需要这样做,您可能需要考虑重新设计多线程以便不需要到。

作为the Microsoft documentation states:

默认情况下,最小线程数设置为系统上的处理器数。您可以使用 SetMinThreads 方法来增加最小线程数。但是,不必要地增加这些值可能会导致性能问题。如果同时启动太多任务,所有任务都可能看起来很慢。在大多数情况下,线程池使用自己的分配线程算法会表现得更好。将最小值减少到少于处理器数量也会损害性能。

【讨论】:

  • 你提到的2秒延迟的信息来源是什么?
  • @AliEzzatOdeh 顺便提到了here。另见here
猜你喜欢
  • 1970-01-01
  • 2018-11-23
  • 1970-01-01
  • 2011-12-16
  • 2013-10-14
  • 1970-01-01
  • 1970-01-01
  • 2015-07-06
相关资源
最近更新 更多