Performance impact of adjusting thread pool

Keywords: C#

        The default minimum number of threads is the number of CPU cores, and the default maximum number of threads is 250 times the number of machine cores. Thread pool scheduling will limit the activated threads to the default minimum number of threads. If there is no thread end, at most two new threads can be invoked per second. Suppose a four core machine. For thread pools, threads that run for a long time or are blocked by I/O are not good candidates. It is not safe to reach the maximum number of threads. On a quad core machine, only the stack of these threads will occupy gigabytes of virtual space, which is likely to cause OOM and out of memory. If this problem exists, you can consider setting the maximum number of threads or activating threads only from a thread safe queue.

        My CPU is six core, + VS2019.

 

1, The code is as follows. Do some tests.

ThreadPool.SetMinThreads(int workerThreads, int completionPortThreads)

Worker threads: the minimum number of new free worker threads to be maintained by the thread pool. (max / min threads)

completionPortThreads: the minimum number of new idle asynchronous I/O threads to be maintained by the thread pool.

public void ThreadUseAndContruction()
{
    // Gets the number of worker threads and one I/O thread in the default thread pool
    ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
    //var minRes = ThreadPool.SetMinThreads(5, 5);
    //var maxRes = ThreadPool.SetMinThreads(5, 5);

    Stopwatch watch = new Stopwatch();
    watch.Start();

    WaitCallback callback = index =>
    {
        Console.WriteLine(String.Format("{0}: Task {1} started", watch.Elapsed, index));
        Thread.Sleep(10000);
        Console.WriteLine(String.Format("{0}: Task {1} finished", watch.Elapsed, index));
    };

    for (int i = 0; i < 20; i++)
    {
        ThreadPool.QueueUserWorkItem(callback, i);
    }
}

        Get the number of working threads and I/O threads in the default thread pool. The result is 6, which is consistent with the number of CPU cores.

1. Set nothing and use the default maximum and minimum number of threads.

 

        By printing the log, it is found that six new threads are created instantly at 0 seconds, 0-5 threads and 6-15 threads are created every second. Until 10s, a thread ends. This is almost one thread will be created every time it ends, plus the original thread created every second.

2.ThreadPool.SetMinThreads(5, 5);

        Although the minimum thread is set to 5 and returns true, 6 new threads are created at 0 seconds. The number of CPU cores is under control.

3.ThreadPool.SetMinThreads(10, 10);

  When the set minimum number of threads is greater than the number of cores, threads will be started according to the set number.

4.ThreadPool.SetMinThreads(8, 8);
   ThreadPool.SetMaxThreads(15, 15);

        Set the maximum and minimum thread limits at the same time. At this time, it can be found that after 0-14 threads are started, new threads are not created until a thread ends. The total number of threads does not exceed 15.

2, I/O thread pool

        . NET prepares a CLR thread pool and an IO thread pool

static void Main(string[] args)
{
            ThreadPool.SetMinThreads(6, 3);
            ThreadPool.SetMaxThreads(6, 3);

            ManualResetEvent waitHandle = new ManualResetEvent(false);

            Stopwatch watch = new Stopwatch();
            watch.Start();

            WebRequest request = HttpWebRequest.Create("http://www.cnblogs.com/");
            request.BeginGetResponse(ar =>
            {
                var response = request.EndGetResponse(ar);
                Console.WriteLine(watch.Elapsed + ": Response Get");

            }, null);

            for (int i = 0; i < 10; i++)
            {
                ThreadPool.QueueUserWorkItem(index =>
                {
                    Console.WriteLine(String.Format("{0}: Task {1} started", watch.Elapsed, index));
                    waitHandle.WaitOne();

                }, i);
            }

            waitHandle.WaitOne();
            Console.ReadLine();
}

Run the above code and get the following results:

        The I/O thread pool was affected by the CLI and did not execute successfully.

        If thread blocking is removed, the result is:

        The IO request is not executed until all CLI threads are executed.   After adjusting the order in which WebRequest operations are placed in the for loop, the result does not change.

        For applications with a large number of activities after a period of inactivity, a small increase in the number of idle threads can significantly improve the throughput.

quote: On thread pool (Part 2): related tests and precautions - Jeffrey Zhao - blog Park

Posted by wolfrat on Fri, 19 Nov 2021 02:19:45 -0800