Understanding Parallel.Invoke, Creating and Reusing Streams

I am trying to understand how Parallel.Invokethreads are created and reused. I ran the following code sample (from MSDN, https://msdn.microsoft.com/en-us/library/dd642243(v=vs.110).aspx ):

using System;
using System.Threading;
using System.Threading.Tasks;

class ThreadLocalDemo
{
        static void Main()
        {
            // Thread-Local variable that yields a name for a thread
            ThreadLocal<string> ThreadName = new ThreadLocal<string>(() =>
            {
                return "Thread" + Thread.CurrentThread.ManagedThreadId;
            });

            // Action that prints out ThreadName for the current thread
            Action action = () =>
            {
                // If ThreadName.IsValueCreated is true, it means that we are not the
                // first action to run on this thread.
                bool repeat = ThreadName.IsValueCreated;

                Console.WriteLine("ThreadName = {0} {1}", ThreadName.Value, repeat ? "(repeat)" : "");
            };

            // Launch eight of them. On 4 cores or less, you should see some repeat ThreadNames
            Parallel.Invoke(action, action, action, action, action, action, action, action);

            // Dispose when you are done
            ThreadName.Dispose();
        }
}

As far as I understand, Parallel.Invoketrying to create 8 threads - one for each action. Thus, it creates the first thread, starts the first, actionand thereby gives the ThreadNamethread. Then it creates the next thread (which another gets ThreadName), etc.

If it cannot create a new thread, it will reuse one of the threads created earlier. In this case, the value repeatwill be true, and we can see it in the console output.

Is that right until here?

(" . 4 , ThreadNames") , , Invoke, : 4 8 , , ( ), Invoke 7 , "repeat".

?

Intelยฎ Core โ„ข i7-2860QM ( 4 , 8 ). "repeat", . Invoke 10 8, :

ThreadName = Thread6
ThreadName = Thread8
ThreadName = Thread6 (repeat)
ThreadName = Thread5
ThreadName = Thread3
ThreadName = Thread1
ThreadName = Thread10
ThreadName = Thread7
ThreadName = Thread4
ThreadName = Thread9

, 9 . , 8 .

, . Parallel.Invoke , ? , ?

+5
3

10 Parallel.Invoke, MaxDegreeOfParallelism ( - ), sheduler , rougly

var actions = new [] { action, action, action, action, action, action, action, action };
var tasks = new Task[actions.Length];
for (int index = 1; index < tasks.Length; ++index)
    tasks[index] = Task.Factory.StartNew(actions[index]);
tasks[0] = new Task(actions[0]);
tasks[0].RunSynchronously();
Task.WaitAll(tasks);

, Task.Factory.StartNew.

int th, io;
ThreadPool.GetMaxThreads(out th, out io);
Console.WriteLine(th);

, 32767. , , Parallel.Invoke ( ), . 8 .

, ? , - . . , Task.Factory.StartNew, , . .

, (repeat) 8 7, , 8- (16 ).

UPDATE, . . . max, . . :

int th, io;
ThreadPool.GetMinThreads(out th, out io);

(, 8). , , , - . , - ( , , , 500 ).

, , 2-3 . 0,3 . , 8 , 500 9-. ( ) 8 , , .

, :

static void Main()
{
    // Thread-Local variable that yields a name for a thread
    ThreadLocal<string> ThreadName = new ThreadLocal<string>(() =>
    {
        return "Thread" + Thread.CurrentThread.ManagedThreadId;
    });

    // Action that prints out ThreadName for the current thread
    Action action = () =>
    {
        // If ThreadName.IsValueCreated is true, it means that we are not the
        // first action to run on this thread.
        bool repeat = ThreadName.IsValueCreated;            
        Console.WriteLine("ThreadName = {0} {1}", ThreadName.Value, repeat ? "(repeat)" : "");
        Thread.Sleep(1000000);
    };
    int th, io;
    ThreadPool.GetMinThreads(out th, out io);
    Console.WriteLine("cpu:" + Environment.ProcessorCount);
    Console.WriteLine(th);        
    Parallel.Invoke(Enumerable.Repeat(action, 100).ToArray());        

    // Dispose when you are done
    ThreadName.Dispose();
    Console.ReadKey();
}

, ( , ), , .

, :

int th, io;
ThreadPool.GetMinThreads(out th, out io);
ThreadPool.SetMinThreads(100, io);

( 100 ), .

+3

( ) . , .

, - , .

. , , . , , , . , , , , , - , (, ).

. , . , โ€‹โ€‹ . , , .

, , , , . . , .

: , , . , . , . .NET, .

+1

   , 9 . , 8 .

- . , : (1) -, , (2) , , (3) . Thread.CurrentThread (2), " ", , (3).

(2) -thread (3) -thread, (2) -thread, , . (2) -thread (2) -thread ( API, ).

, (2) -thread - - 1:1 (2) -thread (3) -thread, , , , , , (3) -thread, .

, "" (2) -thread (3) -thread , , , - (2) -thread (3) -thread .

:

// If ThreadName.IsValueCreated is true, it means that we are not the
// first action to run on this thread.   <-- this refers to (2)-thread, NOT (3)-thread.

Parallel.Invoke ( ) (2) -thread, . (2) -thread , Parallel.Invoke (2) -thread , API. , , (2) -thread. (2) -thread, Parallel.Invoke, - (3) -thread .

, . (2) -thread (3) -thread , Parallel.Invoke - , . :

We do not give any guarantees regarding the order of operations or their parallel execution.

This means that he Invokecan freely perform actions with selected (2) -thread, if he so desires. And this is what you observed.

0
source

Source: https://habr.com/ru/post/1670060/


All Articles