尽管线程池中有可用线程,但Task.Factory.StartNew的启动仍存在很大的延迟

时间:2018-12-03 08:15:35

标签: c# multithreading task

此问题是我先前提出的问题的延续:

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);

重现该错误时,我得到32767作为最大工作线程,32756作为可用工作线程。

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

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

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

1 个答案:

答案 0 :(得分:3)

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

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

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

the Microsoft documentation states

  

默认情况下,最小线程数设置为系统上的处理器数。您可以使用SetMinThreads方法来增加最小线程数。但是,不必要地增加这些值可能会导致性能问题。如果太多任务同时开始,则它们似乎都变慢了。在大多数情况下,线程池使用自己的分配线程算法会更好地执行。将最小值降低到少于处理器数量也会损害性能。