SoFunction
Updated on 2025-03-06

C# uses methods to execute each thread provided in parallel as possible

Perform each operation provided in parallel as possible. How to use.

The simplest and most concise parallelizes serial code.

1. Reload

Invoke(Action[]) Perform each operation provided in parallel as possible.
Invoke(ParallelOptions, Action[]) Perform each of the operations provided and run in parallel as much as possible unless the user cancels the operation.

2. Invoke(Action[])

Perform each operation provided in parallel as possible.

1. Definition

public static void Invoke (params Action[] actions);

parameter
actions    Action[]
To be executed Action Array。

exception
ArgumentNullException
actions parameter为 null。

AggregateException
when actions Array中的任何操作引发异常时引发的异常。

ArgumentException
actionsArray包含 null Elements。

2. Example

The Invoke method is often used in conjunction with other methods, anonymous delegates and lambda expressions to achieve thread synchronization of parallel methods.

// ()method// Use the Invoke method with other methods, anonymous delegates, and lambda expressions.namespace ConsoleApp15
{
    class ParallelInvokeDemo
    {
        /// <summary>
        /// The thread that performs each task may be different.        /// The thread allocation may be different in different executions.        /// The tasks may be executed in any order.        /// </summary>
        static void Main()
        {
            try
            {
                (
                    BasicAction,    // Param #0 - static method
                    () =>           // Param #1 - lambda expression
                    {
                        ("Method=beta, Thread={0}", );
                    },
                    delegate ()     // Param #2 - in-line delegate
                    {
                        ("Method=gamma, Thread={0}", );
                    }
                );
            }
            // Generally, no exception will appear, but if an exception is thrown,            // It will be wrapped in AggregateException and propagated to the main thread.            catch (AggregateException e)
            {
                ("An action has thrown an exception. THIS WAS UNEXPECTED.\n{0}", !.ToString());
            }
        }

        static void BasicAction()
        {
            ("Method=alpha, Thread={0}", );
        }
    }
}
// Running results:/*
Method=beta, Thread=4
Method=alpha, Thread=1
Method=gamma, Thread=10

 */

3. Invoke(ParallelOptions, Action[])

Perform each of the operations provided and run in parallel as much as possible unless the user cancels the operation.

1. Definition

public static void Invoke ( parallelOptions, params Action[] actions);

parameter
parallelOptions    ParallelOptions
An object,The behavior used to configure this operation。

actions    Action[]
Array of operations to be executed。

exception
OperationCanceledException
CancellationToken In parallelOptions set up。

ArgumentNullException
actions parameter为 null。
or - parallelOptions parameter为 null。
AggregateException
when actions Exception raised when any operation in the array throws an exception。

ArgumentException
actionsArray contains null Elements。

ObjectDisposedException
exist parallelOptions Middle and CancellationTokenSource Related CancellationToken Released。

annotation
This method can be used to perform a set of possible parallel operations。 Use structure to pass in ParallelOptions The cancel token enables the caller to cancel the entire operation。

2. Commonly used methods

(
   () => { },
   () => { },
   () => { }
   );

(1) Example 1

  • A task can be broken down into multiple tasks and adopts the idea of ​​dividing and conquering;
  • Avoid dependence between subtasks as much as possible, because subtasks are executed in parallel, so there is no requirement that anyone must be ahead and who must be behind;
  • The main thread must wait until all methods in Invoke have been executed before continuing to execute downwards. It is implied that when designing parallelism in the future, you should consider each Task task as similar as possible. If the difference is large, such as one time is very long and the others are relatively short, such a thread may affect the performance of the entire task. This is very important;
  • There is no fixed order, each task may be executed by a different thread, or it may be the same;
namespace ConsoleApp16
{
    internal class Program
    {
       
        private static void Main(string[] args)
        {
            (args);
            ParallelMothed();
            static void ParallelMothed()
            {
                (Run1, Run2);  //The Run1 and Run2 here are all methods.            }
        }
        static void Run1()
        {
            ("I'm Mission One, I ran for 3s");
            (3000);
        }

        static void Run2()
        {
            ("I'm Mission Two, I ran for 5s");
            (5000);
        }
    }
}
//Run result:/*
 I'm Mission Two, I ran for 5 seconds
 I'm Mission One, I ran for 3 seconds

  */

(2) Example 2

If the method called has parameters, how to deal with it? Similarly, just bring the parameters.

(() => Task1("task1"), () => Task2("task2"), () => Task3("task3"));
// Invoke with parametersusing ;

namespace ConsoleApp17
{
    class ParallelInvoke
    {
        public static void Main(string[] args)
        {
            (args);
            Stopwatch stopWatch = new();
            ("Main thread:{0}ThreadID : {1};start", "Main", );
            ();
            (
                () => Task1("task1"), 
                () => Task2("task2"), 
                () => Task3("task3")
                );
            ();
            ("Main thread:{0}ThreadID : {1};Finish,Shared time{2}ms", "Main", , );
            ();
        }

        private static void Task1(string data)
        {
            (5000);
            ("Task name:{0}ThreadID : {1}", data, );
        }

        private static void Task2(string data)
        {
            ("Task name:{0}ThreadID : {1}", data, );
        }

        private static void Task3(string data)
        {
            ("Task name:{0}ThreadID : {1}", data, );
        }
    }
}
//Run result:/*
 Main thread: Main thread ID: 1; Start
 Task name: task2 thread ID: 4
 Task name: task3 thread ID: 7
 Task name: task1 thread ID: 1
 Main thread: Main thread ID: 1; end, 5020ms in total
  */

(3) Stopwatch class

Provides a set of methods and properties that can be used to accurately measure runtime.

Among them, methods and methods

public class Stopwatch

Use the Stopwatch class to determine the execution time of the application.

// Use the Stopwatch class to determine the execution time of the applicationusing ;
class Program
{
    static void Main(string[] args)
    {
        (args);

        Stopwatch stopWatch = new();
        ();
        (10000);
        ();
        // Get the elapsed time as a TimeSpan value.
        TimeSpan ts = ;

        // Format and display the TimeSpan value.
        string elapsedTime = ("{0:00}:{1:00}:{2:00}.{3:00}",
            , , ,
             / 10);
        ("RunTime " + elapsedTime);
    }
}
//Run result:/*
RunTime 00:00:10.01

 */
// Use the Stopwatch class to calculate performance data.using ;

namespace StopWatchSample
{
    class OperationsTimer
    {
        public static void Main(string[] args)
        {
            (args);

            DisplayTimerProperties();

            ();
            ("Press the Enter key to begin:");
            ();
            ();

            TimeOperations();
        }

        public static void DisplayTimerProperties()
        {
            // Display the timer frequency and resolution.
            if ()
            {
                ("Operations timed using the system's high-resolution performance counter.");
            }
            else
            {
                ("Operations timed using the DateTime class.");
            }

            long frequency = ;
            ("  Timer frequency in ticks per second = {0}",frequency);
            long nanosecPerTick = (1000L * 1000L * 1000L) / frequency;
            ("  Timer is accurate within {0} nanoseconds",nanosecPerTick);
        }

        private static void TimeOperations()
        {
            long nanosecPerTick = (1000L * 1000L * 1000L) / ;
            const long numIterations = 10000;

            // Define the operation title names.
            string[] operationNames = {"Operation: (\"0\")",
                                           "Operation: (\"0\")",
                                           "Operation: (\"a\")",
                                           "Operation: (\"a\")"};

            // Time four different implementations for parsing
            // an integer from a string.

            for (int operation = 0; operation <= 3; operation++)
            {
                // Define variables for operation statistics.
                long numTicks = 0;
                long numRollovers = 0;
                long maxTicks = 0;
                long minTicks = ;
                int indexFastest = -1;
                int indexSlowest = -1;
                Stopwatch time10kOperations = ();

                // Run the current operation 10001 times.
                // The first execution time will be tossed
                // out, since it can skew the average time.

                for (int i = 0; i <= numIterations; i++)
                {
                    long ticksThisTime = 0;
                    int inputNum;
                    Stopwatch timePerParse;

                    switch (operation)
                    {
                        case 0:
                            // Parse a valid integer using
                            // a try-catch statement.
                            // Start a new stopwatch timer.
                            timePerParse = ();

                            try
                            {
                                inputNum = ("0");
                            }
                            catch (FormatException)
                            {
                                inputNum = 0;
                            }

                            // Stop the timer, and save the
                            // elapsed ticks for the operation.

                            ();
                            ticksThisTime = ;
                            break;
                        case 1:
                            // Parse a valid integer using
                            // the TryParse statement.

                            // Start a new stopwatch timer.
                            timePerParse = ();

                            if (!("0", out inputNum))
                            {
                                inputNum = 0;
                            }

                            // Stop the timer, and save the
                            // elapsed ticks for the operation.
                            ();
                            ticksThisTime = ;
                            break;
                        case 2:
                            // Parse an invalid value using
                            // a try-catch statement.

                            // Start a new stopwatch timer.
                            timePerParse = ();

                            try
                            {
                                inputNum = ("a");
                            }
                            catch (FormatException)
                            {
                                inputNum = 0;
                            }

                            // Stop the timer, and save the
                            // elapsed ticks for the operation.
                            ();
                            ticksThisTime = ;
                            break;
                        case 3:
                            // Parse an invalid value using
                            // the TryParse statement.

                            // Start a new stopwatch timer.
                            timePerParse = ();

                            if (!("a", out inputNum))
                            {
                                inputNum = 0;
                            }

                            // Stop the timer, and save the
                            // elapsed ticks for the operation.
                            ();
                            ticksThisTime = ;
                            break;

                        default:
                            break;
                    }

                    // Skip over the time for the first operation,
                    // just in case it caused a one-time
                    // performance hit.
                    if (i == 0)
                    {
                        ();
                        ();
                    }
                    else
                    {

                        // Update operation statistics
                        // for iterations 1-10000.
                        if (maxTicks < ticksThisTime)
                        {
                            indexSlowest = i;
                            maxTicks = ticksThisTime;
                        }
                        if (minTicks > ticksThisTime)
                        {
                            indexFastest = i;
                            minTicks = ticksThisTime;
                        }
                        numTicks += ticksThisTime;
                        if (numTicks < ticksThisTime)
                        {
                            // Keep track of rollovers.
                            numRollovers++;
                        }
                    }
                }

                // Display the statistics for 10000 iterations.

                ();
                long milliSec = ;
                ();
                ("{0} Summary:", operationNames[operation]);
                ("  Slowest time:  #{0}/{1} = {2} ticks",
                    indexSlowest, numIterations, maxTicks);
                ("  Fastest time:  #{0}/{1} = {2} ticks",
                    indexFastest, numIterations, minTicks);
                ("  Average time:  {0} ticks = {1} nanoseconds",
                    numTicks / numIterations,
                    (numTicks * nanosecPerTick) / numIterations);
                ("  Total time looping through {0} operations: {1} milliseconds",
                    numIterations, milliSec);
            }
        }
    }
}
//Run result:/*
Operations timed using the system's high-resolution performance counter.
  Timer frequency in ticks per second = 10000000
  Timer is accurate within 100 nanoseconds

 */

method

Start or continue to measure the running time of a certain time interval.

There are examples in the previous example.

public void Start ();

method

Stop measuring the running time of a certain time interval.

public void Stop ();

There are examples in the previous example.

This is the article about each thread provided by C# using methods to perform parallel execution as much as possible. For more related C# parallel execution, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!