C # Parallel. Invoke in Parallel programming,
I. Basic Knowledge
Parallel Programming: parallel programming refers to software development code. It can execute multiple computing tasks at the same time to improve execution efficiency and performance. Therefore, in the design process, many tasks are generally divided into several independent subtasks, which do not consider their dependencies and order. In this way, we can use parallel programming. However, we all know that the parallel design of multi-core processors uses shared memory. If we do not consider concurrency issues, there will be many exceptions that will not achieve our expected results. But fortunately, NET Framework4.0 introduced the Task Parallel Library (TPL) to implement a Parallel development framework based on the Task design without the need to process repeated and complex threads. It supports data parallelism, task parallelism, and pipeline. The core is mainly Task, but we can use the static class provided by Parallel to perform simple parallelism as follows.
Parallel. Invoke implements Parallel development for a given task
Parallel. For provides cyclic iterative Parallel development For a fixed number of tasks
Parallel. Foreach provides cyclic iterative parallel development for a fixed number of tasks
Note: All Parallel development is not as simple as replacing For or Foreach with Parallel. For and Parallel. Foreach.
PS: starting from a simple Invoke, I will gradually explore the main knowledge points of parallel development and summarize the accumulation in my learning process. I will refer to other excellent blog posts in the blog.
Rain asynchronous programming: lightweight thread synchronization primitive object
First of all, thank you for your great help in my study of parallel development.
Ii. Use of Parallel. Invoke in Parallel
First, let's take a look at its two overload methods:
public static void Invoke(params Action[] actions); public static void Invoke(ParallelOptions parallelOptions, params Action[] actions);
Invoke mainly accepts the params delegate actions. For example, if we want to execute three tasks at the same time, we can use
Method 1
Parallel. Invoke () => Task1 (), () => Task2 (), () => Task3 ());
Method 2
Parallel. Invoke (Task1, Task2, Task3 );
Method 3
Parallel. Invoke (
() =>
{
Task1 ();
},
Task2,
Delegate () {Task3 (); console. write ('Do someting! ');});
In this way, Invoke implements parallel development of Task 1, Task 2, and task 3. The following example is used to describe their execution rules. And the use of two overload methods.
Iii. Demo
1. Demo 1:
Public class ParallelInvoke {// <summary> // Invoke method 1 action /// </summary> public void Client1 () {Stopwatch stopWatch = new Stopwatch (); Console. writeLine ("main Thread: {0} Thread ID: {1}; start", "Client1", Thread. currentThread. managedThreadId); stopWatch. start (); Parallel. invoke () => Task1 ("task1"), () => Task2 ("task2"), () => Task3 ("task3"); stopWatch. stop (); Console. writeLine ("main Thread: {0} Thread ID: {1}; end, total time: {2} ms", "Client1", Thread. currentThread. managedThreadId, stopWatch. elapsedMilliseconds);} private void Task1 (string data) {Thread. sleep (1, 5000); Console. writeLine ("Task Name: {0} Thread ID: {1}", data, Thread. currentThread. managedThreadId);} private void Task2 (string data) {Console. writeLine ("Task Name: {0} Thread ID: {1}", data, Thread. currentThread. managedThreadId);} private void Task3 (string data) {Console. writeLine ("Task Name: {0} Thread ID: {1}", data, Thread. currentThread. managedThreadId );}}
Result After running:
We can see that the three methods for executing tasks by Invoke mainly have the following features:
1. There is no fixed sequence, and each Task may be executed by different threads or the same;
2. The main thread must wait until all the methods in the Invoke are executed and return to continue to execute. In this way, when we design parallel tasks in the future, we should consider that each Task should be as similar as possible, if the difference is large, for example, if one thread lasts for a very long time and the other is shorter, such a thread may affect the performance of the entire task. This is very important.
3. Parallel Execution is implemented in a very simple way, so we don't need to consider the thread issue. The main Framework already controls the thread pool for us.
Ps: What if there is an exception? Added Task4.
2. Demo2
Public class ParallelInvoke {// <summary> // Invoke method 1 action /// </summary> public void Client1 () {Stopwatch stopWatch = new Stopwatch (); Console. writeLine ("main Thread: {0} Thread ID: {1}; start", "Client1", Thread. currentThread. managedThreadId); stopWatch. start (); try {Parallel. invoke () => Task1 ("task1"), () => Task2 ("task2"), () => Task3 ("task3"), delegate () {throw new Exception ("I sent an Exception here") ;}) ;}catch (aggresponexception AE) {foreach (var ex in AE. innerExceptions) Console. writeLine (ex. message);} stopWatch. stop (); Console. writeLine ("main Thread: {0} Thread ID: {1}; end, total time: {2} ms", "Client1", Thread. currentThread. managedThreadId, stopWatch. elapsedMilliseconds );}}
Mainly refer to delegate () {throw new Exception ("I sent an Exception here");} added this delegate Task3. then let's see the result:
Here we find that even if an exception program is executed, the execution of other tasks will not be affected.
3. Use the demo3 overload method ParallelOptions.
To understand ParallelOptions, asynchronous programming is recommended: lightweight thread synchronization primitive objects are described in great detail.
We mainly understand two parameters:
Cancelling the CancellationToken control thread
MaxDegreeOfParallelism sets the maximum number of threads, and sometimes it may run all the kernels. To improve the stability of other applications, it is necessary to limit the kernel involved.
What is the result from the code below?
Public class ParallelInvoke {// defines the CancellationTokenSource control to cancel readonly CancellationTokenSource _ cts = new CancellationTokenSource (); /// <summary> /// Invoke method 1 action /// </summary> public void Client1 () {Console. writeLine ("main Thread: {0} Thread ID: {1}; start {2}", "Client3", Thread. currentThread. managedThreadId, DateTime. now); var po = new ParallelOptions {CancellationToken = _ cts. token, // control the thread to cancel MaxDegreeOfParallelism = 3 // set the maximum number of threads 3 and observe the thread ID changes carefully}; Parallel. invoke (po, () => Task1 ("task1"), () => Task5 (po), Task6); Console. writeLine ("main Thread: {0} Thread ID: {1}; end {2}", "Client3", Thread. currentThread. managedThreadId, DateTime. now);} private void Task1 (string data) {Thread. sleep (1, 5000); Console. writeLine ("Task Name: {0} Thread ID: {1}", data, Thread. currentThread. managedThreadId );}
// Print the number private void Task5 (ParallelOptions po) {Console. writeLine ("Enter Task5 Thread ID: {0}", Thread. currentThread. managedThreadId); int I = 0; while (I <100) {// determines whether the if (po. cancellationToken. isCancellationRequested) {Console. writeLine ("canceled. "); Return;} Thread. sleep (1, 100); Console. write (I + ""); Interlocked. increment (ref I) ;}/// <summary> /// cancel 10 seconds later /// </summary> private void Task6 () {Console. writeLine ("Enter the cancel task, Task6 Thread ID: {0}", Thread. currentThread. managedThreadId); Thread. sleep (1000*10); _ cts. cancel (); Console. writeLine ("initiate a cancellation request ........... ");}}
Execution result:
The program results show the following features:
1. The number of threads in the execution process cannot exceed 3.
2. cancelling CancellationTokenSource/CancellationToken control tasks.
Iv. Summary
Note the following features when using Parallel. Invoke:
1. If there is no specific order, the methods in Invoke will be returned only after they are fully executed, but even if exceptions are still completed during execution, it is just a very simple parallel processing method, the feature is simple, so we don't need to consider the thread issue.
2. It takes a long time to design an Invoke, which will affect the efficiency and performance of the entire Invoke. We must consider this when designing each task.
3. The Invoke parameter is the delegate method.
4. Of course, Invoke has overhead in each call. It may not be better than serial in parallel. It is only possible to perform multiple tests and tuning in the kernel environment according to the actual situation.
5. Exception Handling is complicated.