Talking about the thread pool (bottom): Related Test and matters needing attention

Source: Internet
Author: User

Three months, a full three months, I suddenly found that I have three months ago a small series of articles did not end, I still owe an experiment! The thread pool is. NET, almost all of the asynchronous functions depend on the thread pool. We discussed the role of the thread pool, the existence of a separate thread pool, and a description of the CLR thread pool and IO thread pools. But these instructions may be "abstract", so we still have to experiment to "verify" these instructions. In addition, I think it is very important to design some tests for a certain "conjecture", and if you have a slight lack of ability, try to exercise and improve it.

Use and creation of CLR threads

First, we prepare this piece of code:

public static void Threaduseandconstruction () {    threadpool.setminthreads (5, 5);//Set min thread to 5    ThreadPool . SetMaxThreads (12, 12); Set Max thread to    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 <; i++)    {        ThreadPool.QueueUserWorkItem (callback, I);}    }

This piece of code is simple. First, set the minimum and maximum number of threads for the thread pool to 5 and 12, and then push the 20 tasks continuously into the thread pools, each of which prints the current time at execution, and then waits 10 seconds. So what do you think about the output of this piece of code?

Expand

The high 0 We simply ignore, we only observe the "second" and the following accuracy of time. After a simple observation of this data, we find that we can pinpoint the time to 0.5 seconds to describe what happens at each moment:

    1. 0 seconds: Task 0 to Task 3, a total of 4 tasks to start execution.
    2. 1-3 seconds: Task 4 to Task 8 is executed sequentially, with a interval of 0.5 seconds.
    3. 3-6 seconds: Task 8 to Task 11 is executed sequentially, with a interval of 1 seconds.
    4. 10 seconds: Task 0 to Task 3 execution complete, task 12 to task 15 start execution.
    5. 11 to 12.5 seconds: a new task (16 to 19) is started immediately after each old task (4 to 7) is executed.
    6. 13 to 22.5 seconds: the remaining tasks (8 to 19) end in turn.

Have you guessed it right? I did not guess right, because there are two points:

    • The original minimum number of threads is 5 o'clock, and only 4 threads can execute immediately. After a further attempt, the minimum number of threads is 10 o'clock, and only 9 threads can be executed immediately.
    • The original thread pool created threads is not always "2 per second", and some of the data says "no more than 2 per second" is indeed the exact word.

However, we have verified the following conclusions:

    • The number of threads in the online pool is within range of the minimum thread, and as many tasks as possible are executed immediately.
    • The thread pool uses a frequency of not more than 2 per second to create threads (1 seconds one or 0.5 seconds one).
    • When the maximum number of threads in the thread pool is reached (6 seconds), the creation of a new thread is stopped.
    • When the old task finishes executing, the new task executes immediately.

Of course, since we've already "learned" how the thread pool works, there's a tendency for the results to be "justified". To reduce this possibility, you need to design a more complete experiment to "explain" the problem. You can also follow this point for more in-depth exploration.

Threads in the thread pool are "public"

Instead of creating threads on their own, we chose to use the thread pool for some reason. However, since we are using the thread pool, there are some extra things to note.

First, we need to make a clear idea that a thread does not "belong" to any task, or that the task does not "own" the thread. We just borrowed a thread to do the work, and we'll return it when we're done. In other words, it is meaningless for the task to modify the thread's information (name, priority, language culture, etc.) at execution time, and the task should not rely on these states of the thread. Remember the difference between QueueUserWorkItem and Unsafequeueuserworkitem mentioned in the previous article? If your task depends on something, please prepare it yourself. The thread state in the thread pool is unreliable. Of course, try not to do anything else directly to the current thread.

Second, due to the size limit of the thread pool, there may be situations where deadlocks can occur at some point:

static void WaitCallback (object handle) {    ManualResetEvent WaitHandle = (manualresetevent) handle;    for (int i = 0; i <, i++)    {ThreadPool.QueueUserWorkItem (state = +        {            int) index = (int) state;            if (index = = 9)            {                waithandle.set ();//Release All             }            else            {                waithandle.waitone ();//wait< c13/>}}        , i);}    } public static void DeadLock () {    ManualResetEvent waitHandle = new ManualResetEvent (false);    Threadpool.setmaxthreads (5, 5);    ThreadPool.QueueUserWorkItem (WaitCallback, waitHandle);    WaitHandle.WaitOne ();}

In the above code, WaitHandle will block forever. Because we put 10 tasks into the thread pool, only the last one will open the WaitHandle, and the rest of the tasks are blocked on this WaitHandle. Note, however, that we use the SetMaxThreads method to limit the maximum number of threads to 5 so that the 10th task does not execute at all, thus entering the deadlock. The simplest way to avoid this problem is to increase the maximum number of threads, but this can create many threads that are not working, resulting in a waste of resources. Therefore, it is best to redesign the parallel algorithm, and always remember: "Do not block thread constructor threads."

It is one of the most common problems in parallel algorithms to use threads reasonably and effectively (neither much nor many are blocked). For example, let you design an algorithm that computes the Fibonacci sequence in parallel, creating two new tasks each time you compute FIB (n) to parallel compute FIB (n-1) and fib (n-2) and wait for them to end, causing the above deadlock (or a large number of threads). How to solve this problem? You can take a look at the new task Parallel class library in. NET 4.0, which provides a rich and easy-to-use parallel computing API that saves us a lot of work 1.

Finally, it is time to remember which features in the system depend on the thread pool. For example, requests in ASP. NET also use the CLR thread pool, so should you use ThreadPool? Should I use the asynchronous invocation of the delegate directly? Should you adjust the maximum and minimum lines of the thread pool? These questions do not determine the answer, which requires you to judge according to the actual situation.

CLR thread pool and IO thread pool

When I first learned that. NET prepares a CLR thread pool and an IO thread pool, I wonder, is there really no relationship between the two? Do they affect each other? So I did one of these tests:

public static void Iothread () {    threadpool.setminthreads (5, 3);    Threadpool.setmaxthreads (5, 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 < i++)    {        ThreadPool.QueueUserWorkItem (index = +        {            Console.WriteLine ( String.Format ("{0}: Task {1} started", watch. Elapsed, index));            WaitHandle.WaitOne ();        }, I);    }    WaitHandle.WaitOne ();}

The resulting result is this:

00:00:00.0923543:task 0 started00:00:00.1152495:task 2 started00:00:00.1153073:task 3 Started00:00:00.1152439:task 1 s Tarted00:00:01.0976629:task 4 Started00:00:01.5235481:response Get

As you can see, we set the maximum number of threads for the CLR thread pool to 5, and deliberately "block" the thread pool with a similar approach as in the previous example, while only 5 of the tasks are executed, which means that the thread pool is actually blocked, and the goal is to see if an IO asynchronous request can get a correct response in this case. The answer is yes, the callback function of the IO asynchronous request executes normally. This means that although the CLR thread pool is running out, there does seem to be an additional IO thread pool that handles asynchronous callbacks for IO. Thus, the CLR thread pool and the IO thread pool are not affected. In addition, judging from the class library designed by the. NET Framework, it is true that the two are differentiated, for example:

public static class ThreadPool {public    static bool GetAvailableThreads (out int workerthreads, out int Completionportt Hreads);}

However, this does not mean that an asynchronous IO request can be initiated after the thread in the CLR threads pool is exhausted. For example, you might try to put the WebRequest action in this example behind a for loop (to make sure that the CLR thread pool is running out of threads), and that you will find that the call to the Begingetrequest method throws an exception prompting you to say that there are no extra threads in the thread pool. From this perspective, it is true that the CLR thread pool is still likely to affect asynchronous IO operations (thanks to Xiongli, "This is determined by the implementation")--although this is not normally the case in ordinary applications.

In fact, in the IO thread pool can also carry out some other experiments. For example, you can reduce the maximum number of threads in the IO thread pool, and then launch multiple asynchronous IO requests at once, observing their callback function execution time. Why don't you do it by yourself?

Related articles
    • Discussion on thread pool (top): The role of thread pool and CLR thread pool
    • Discussion on thread pool (middle): function of independent thread pool and IO thread pool
    • Talking about the thread pool (bottom): Related Test and matters needing attention

Note 1:.net 4.0 has been significantly enhanced in multithreading, and in addition to the Task Parallel class library, the parallel Library has been incorporated into the framework. In addition,. NET 4.0 provides a number of thread-safe parallel containers, as well as lightweight countdownlatch, Semaphoreslim, spinwait and other commonly used components, both learning and use are excellent examples.

Talking about the thread pool (bottom): Related Test and matters needing attention

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.