Chiamata parallela in C#

Chiamata parallela in C#

Metodo di richiamo parallelo in C# con esempi

In questo articolo parlerò del Metodo di richiamo parallelo in C# con esempi. Il metodo Parallel Invoke in C# è uno dei metodi statici più utilizzati della classe Parallel. Finora abbiamo utilizzato un Parallel For Loop e Ciclo Foreach parallelo per eseguire lo stesso blocco di codice più volte in parallelo. Tuttavia, a volte vogliamo invocare metodi diversi in parallelo che non fanno parte del blocco di codice di un ciclo. Per questo, possiamo usare il metodo Parallel Invoke in C#.

Esempio per comprendere il metodo di richiamo parallelo in C#

Il metodo Parallel Invoke in C# viene utilizzato per avviare più attività che verranno eseguite in parallelo. Creiamo prima un esempio in cui invocheremo tre metodi indipendenti in sequenza e quindi riscriveremo lo stesso esempio in cui invocheremo gli stessi tre metodi indipendenti in parallelo usando il metodo Parallel Invoke. Nell'esempio seguente, abbiamo chiamato Method1, Method2 e Method3 e quindi abbiamo registrato il tempo impiegato da questi tre metodi per completare l'esecuzione nella finestra della console.

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

namespace ParallelProgrammingDemo
{
    public class Program
    {
        static void Main()
        {
            Stopwatch stopWatch = new Stopwatch();
            
            stopWatch.Start();
            //Calling Three methods sequentially
            Method1();
            Method2();
            Method3();
            stopWatch.Stop();
            
            Console.WriteLine($"Sequential Execution Took {stopWatch.ElapsedMilliseconds} Milliseconds");
            Console.ReadKey();
        }
        static void Method1()
        {
            Task.Delay(200);
            Console.WriteLine($"Method 1 Completed by Thread={Thread.CurrentThread.ManagedThreadId}");
        }
        static void Method2()
        {
            Task.Delay(200);
            Console.WriteLine($"Method 2 Completed by Thread={Thread.CurrentThread.ManagedThreadId}");
        }
        static void Method3()
        {
            Task.Delay(200);
            Console.WriteLine($"Method 3 Completed by Thread={Thread.CurrentThread.ManagedThreadId}");
        }
    }
}
Risultato:

Come puoi vedere nell'immagine sopra, tutti e tre i metodi vengono eseguiti da un singolo thread e ci vorranno circa 18 millisecondi nella mia macchina per completare l'esecuzione. Ora vedremo lo stesso esempio usando il metodo Parallel.Invoke che eseguirà questi tre metodi parallelamente. Quello che dobbiamo fare è passare i nomi dei metodi al metodo Parallel.Invoke come mostrato nell'immagine sottostante.

Il codice di esempio completo è riportato di seguito.

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

namespace ParallelProgrammingDemo
{
    public class Program
    {
        static void Main()
        {
            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();

            //Calling Three methods Parallely
            Parallel.Invoke(
                 Method1, Method2, Method3
            );

            stopWatch.Stop();
            Console.WriteLine($"Parallel Execution Took {stopWatch.ElapsedMilliseconds} Milliseconds");

            Console.ReadKey();
        }
        static void Method1()
        {
            Task.Delay(200);
            Console.WriteLine($"Method 1 Completed by Thread={Thread.CurrentThread.ManagedThreadId}");
        }
        static void Method2()
        {
            Task.Delay(200);
            Console.WriteLine($"Method 2 Completed by Thread={Thread.CurrentThread.ManagedThreadId}");
        }
        static void Method3()
        {
            Task.Delay(200);
            Console.WriteLine($"Method 3 Completed by Thread={Thread.CurrentThread.ManagedThreadId}");
        }
    }
}
Risultato:

Come puoi vedere, i tre diversi metodi vengono eseguiti da tre thread diversi e anche sulla mia macchina sembrano 49 millisecondi. Se osservi, ci vuole più tempo rispetto all'esecuzione sequenziale. Questo perché il compito che i tre metodi stanno eseguendo è molto piccolo. Quindi, devi sempre eseguire una misurazione delle prestazioni prima di selezionare se desideri eseguire i metodi in parallelo o in sequenza.

Esempio per richiamare diversi tipi di metodi utilizzando Parallel.Invoke in C#:

L'esempio seguente mostra come utilizzare il metodo Parallel Invoke in C# con metodi normali, metodi anonimi (delegati) ed espressioni lambda.

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

namespace ParallelProgrammingDemo
{
    public class Program
    {
        static void Main()
        {
            Parallel.Invoke(
                 NormalAction, // Invoking Normal Method
                 delegate ()   // Invoking an inline delegate 
                 {
                     Console.WriteLine($"Method 2, Thread={Thread.CurrentThread.ManagedThreadId}");
                 },
                () =>   // Invoking a lambda expression
                {
                    Console.WriteLine($"Method 3, Thread={Thread.CurrentThread.ManagedThreadId}");
                }
            );
            Console.WriteLine("Press any key to exist.");
            Console.ReadKey();
        }
        static void NormalAction()
        {
            Console.WriteLine($"Method 1, Thread={Thread.CurrentThread.ManagedThreadId}");
        }
    }
}
Risultato:

Il metodo Parallel Invoke viene utilizzato per eseguire una serie di operazioni (azioni) in parallelo. Come puoi vedere nell'output sopra, vengono creati tre thread per eseguire tre azioni, il che dimostra che questo metodo Invoke parallelo esegue le azioni in parallelo.

Nota: Il metodo Parallel Invoke in C# non offre alcuna garanzia sull'ordine in cui vengono eseguite le azioni. Ogni volta che esegui il codice, potresti ottenere un diverso ordine di output. Un altro punto importante che devi ricordare è che questo metodo tornerà quando tutte le azioni invocate da questo metodo completeranno la loro esecuzione.

Classe ParallelOptions in C#

Come abbiamo già discusso, utilizzando le Opzioni Parallele istanza di classe, possiamo limitare il numero di metodi di ciclo in esecuzione contemporaneamente. La stessa cosa può essere fatta anche con il metodo Invoke. Quindi, utilizzando il Grado di parallelismo possiamo specificare il numero massimo di thread da utilizzare per eseguire il programma.

Esempio da capire Classe ParallelOptions in C# con metodo di richiamo parallelo

Nell'esempio seguente, stiamo creando sette azioni senza specificare un limite al numero di attività parallele. Quindi, in questo esempio, è possibile che tutte e sette le azioni possano essere eseguite contemporaneamente.

Come puoi vedere nell'esempio seguente, chiamiamo DoSomeTask metodo sette volte utilizzando il metodo Parallel Invoke. Come parte di DoSomeTask metodo, stiamo solo stampando due messaggi con una pausa di 5000 millisecondi tra di loro. I messaggi mostrano quando l'attività è iniziata e terminata e da quale thread in modo da comprendere l'ordine di esecuzione.

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

namespace ParallelProgrammingDemo
{
    public class ParallelInvoke
    {
        static void Main()
        {
            Parallel.Invoke(
                    () => DoSomeTask(1),
                    () => DoSomeTask(2),
                    () => DoSomeTask(3),
                    () => DoSomeTask(4),
                    () => DoSomeTask(5),
                    () => DoSomeTask(6),
                    () => DoSomeTask(7)
                );
            Console.ReadKey();
        }
        static void DoSomeTask(int number)
        {
            Console.WriteLine($"DoSomeTask {number} started by Thread {Thread.CurrentThread.ManagedThreadId}");
            //Sleep for 5000 milliseconds
            Thread.Sleep(5000);
            Console.WriteLine($"DoSomeTask {number} completed by Thread {Thread.CurrentThread.ManagedThreadId}");
        }
    }
}

Ora esegui l'applicazione e vedi l'output come mostrato di seguito. L'output può variare nella tua macchina.

Puoi vedere nell'output sopra che ciascuna delle sette attività è iniziata prima che tutte le altre fossero completate, il che dimostra che tutte le sette attività vengono eseguite contemporaneamente. Per limitare il parallelismo, ovvero per limitare il numero di thread da eseguire contemporaneamente, è necessario utilizzare la classe ParallelOptions. Dobbiamo passare l'oggetto di ParallelOptions al primo parametro del metodo Invoke.

Esempio per limitare il numero di thread per eseguire i metodi:

Nell'esempio seguente abbiamo impostato MaxDegreeOfParallelism su 3 della classe ParallelOptions che limiterà l'uso di un massimo di tre thread per invocare tutti i metodi.

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

namespace ParallelProgrammingDemo
{
    public class ParallelInvoke
    {
        static void Main()
        {
            //Allowing three task to execute at a time
            ParallelOptions parallelOptions = new ParallelOptions
            {
                MaxDegreeOfParallelism = 3
            };
            //parallelOptions.MaxDegreeOfParallelism = System.Environment.ProcessorCount - 1;

            //Passing ParallelOptions as the first parameter
            Parallel.Invoke(
                    parallelOptions,
                    () => DoSomeTask(1),
                    () => DoSomeTask(2),
                    () => DoSomeTask(3),
                    () => DoSomeTask(4),
                    () => DoSomeTask(5),
                    () => DoSomeTask(6),
                    () => DoSomeTask(7)
                );
            Console.ReadKey();
        }
        static void DoSomeTask(int number)
        {
            Console.WriteLine($"DoSomeTask {number} started by Thread {Thread.CurrentThread.ManagedThreadId}");
            //Sleep for 500 milliseconds
            Thread.Sleep(5000);
            Console.WriteLine($"DoSomeTask {number} completed by Thread {Thread.CurrentThread.ManagedThreadId}");
        }
    }
}
Risultato:

Come puoi vedere dall'output sopra, le prime tre attività sono state avviate contemporaneamente poiché abbiamo impostato il grado di parallelismo su 3. Quando una delle attività completa la sua esecuzione, un'altra attività cominciato. Questo processo continuerà fino a quando tutte le azioni non avranno completato il loro lavoro. Ma il punto più importante che devi ricordare è che in un dato momento non vengono eseguite più di tre attività.

Nel prossimo articolo parlerò di Come utilizzare il grado massimo di parallelismo in C# con esempi. Qui, in questo articolo, provo a spiegare il Metodo di richiamo parallelo in C# con esempi. Spero che tu abbia compreso la necessità e l'uso del metodo Parallel Invoke in C# con esempi.