尽管在线程池中有可用的线程,但Task.Factory.StartNew的启动时间很长

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了尽管在线程池中有可用的线程,但Task.Factory.StartNew的启动时间很长相关的知识,希望对你有一定的参考价值。

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

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作为Max工作线程,32756作为可用工作线程。

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

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

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

答案

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

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

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

作为the Microsoft documentation states

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

以上是关于尽管在线程池中有可用的线程,但Task.Factory.StartNew的启动时间很长的主要内容,如果未能解决你的问题,请参考以下文章

Cartographer中的线程池操作

五种线程池的分类和作用

五种线程池的分类和作用

为啥线程没有在线程池中重用?

C++:尽管发送了数据,但 Recv 永远阻塞

Java 线程池