简体   繁体   中英

why the primary thread is blocked when using Parallel.ForEach

Below is my code:

class Program
{
    static void Main(string[] args)
    {
        Test();
    }

    static void Test()
    {
        string[] strList = { "first", "second", "third" };
        Parallel.ForEach(strList, currStr =>
        {
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} is handling {currStr}");
            if (Thread.CurrentThread.ManagedThreadId != 1)  //if not primary thread, sleep for 5 secs
            {
                Thread.Sleep(5000);
            }
        });
        Console.WriteLine($"Here is thread {Thread.CurrentThread.ManagedThreadId}");
        ...
        doMoreWork();
        ...
    }
}

so Parallel.ForEach fetches two threads from the ThreadPool plus existing primary thread. And the output is:

Thread 1 is handling first

Thread 3 is handling second

Thread 4 is handling third

and after 5 seconds:

Here is Thread 1

Obviously, thread 1(primary thread) was blocked. But why wasbthe primary thread blocked? I can kind of get the idea that primary thread is blocked to wait for other threads to finish their jobs. But isn't that very inefficient, because the primary thread is blocked, it cannot continue to execute doMoreWork() until all other threads finish.

How else could this possibly work? The purpose of a parallel for loop is to speed up a calculation by performing parts of it in parallel. The program cannot continue until all parts of the loop have completed (and the final result of the calculation can be computed). It's purpose is not to hand off work to execute asynchronously while the initiating thread continues on its way. You're using the wrong tool for the job. You should look into Task objects.

It isn't inefficient, it is simply the way you have coded it. While parallel thread execution is useful, so is sequential execution. The main purpose for the Parallel.Foreach is to iterator over an enumeration by partitioning the enumeration across multiple threads. Lets say for example the Foreach loop calculates a value by applying operations to each item in the enumeration. You then want to use this single value in a call to doMoreWork. If the Foreach loop and the doMoreWork executed in parallel you would have to introduce some form of wait to ensure the foreach completed before calling doMoreWork.

You might want to take a look at the Task Class documentation and examples. If you really want to have a Parallel.Foreach and doMoreWork running in separate threads at the same time you can uses Task.Run to start a function (or lambda), then independently wait on these to finish.

I will note that parallel execution doesn't guarantee efficient or speed. There are many factors to consider such as Amdahl's law , the effect of locking memory to ensure coherence, total system resources, etc. It's a very big topic.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM