C#.Rihter.Parallel For, ForEach, Invoke

tasks that can be done in parallel

        static void Main(string[] args)
        {
            Parallel.For(1, 10, i => DoWork(i));
            Thread.Sleep(12000);
        }

        static void DoWork(int i)
        {
            Thread.Sleep(1000);
            Console.WriteLine(i);
        }
    }
// or we can use parallel options to adjust threads
            
ParallelOptions options = new ParallelOptions();
options.CancellationToken = new CancellationTokenSource().Token;
options.MaxDegreeOfParallelism = -1; // default
options.TaskScheduler = TaskScheduler.Default; // default
Parallel.For(1, 3, options, DoWork(i));

output

1
2
4
3
5
6
7
8
9

Or the same with parallel

Parallel.ForEach(collection, item => DoWork(item));

Or the same with invoke

        static void Main(string[] args)
        {
            Parallel.Invoke(() => Console.WriteLine("Invoke 1"),
                () => Console.WriteLine("Invoke 2"),
                () => Console.WriteLine("Invoke 3")
            );
            
            Thread.Sleep(12000);
        }

output

Invoke 2
Invoke 3
Invoke 1

PARALLEL WITH INIT BODY FINISH LAMDAS

            int[] nums = Enumerable.Range(1, 3).ToArray();
            long total = 0;

            Parallel.ForEach<int, long>(
                nums,
                () => 0,
                (j, loop, subtotal) =>
                {
                    subtotal += j;
                    return subtotal;
                },
                (finalResult) => Interlocked.Add(ref total, finalResult)
            );
            
            
            Thread.Sleep(2000);
            Console.WriteLine("Result is {0:N0}", total);

One good example from stackOverflow

public void MyParallelizedMethod()
{
    // Shared variable. Not thread safe
    var itemCount = 0; 

    Parallel.For(myEnumerable, 
    // localInit - called once per Task.
    () => 
    {
       // Local `task` variables have no contention 
       // since each Task can never run by multiple threads concurrently
       var sqlConnection = new SqlConnection("connstring...");
       sqlConnection.Open();

       // This is the `task local` state we wish to carry for the duration of the task
       return new 
       { 
          Conn = sqlConnection,
          RunningTotal = 0
       }
    },
    // Task Body. Invoked once per item in the batch assigned to this task
    (item, loopState, taskLocals) =>
    {
      // ... Do some fancy Sql work here on our task's independent connection
      using(var command = taskLocals.Conn.CreateCommand())
      using(var reader = command.ExecuteReader(...))
      {
        if (reader.Read())
        {
           // No contention for `taskLocal`
           taskLocals.RunningTotal += Convert.ToInt32(reader["countOfItems"]);
        }
      }
      // The same type of our `taskLocal` param must be returned from the body
      return taskLocals;
    },
    // LocalFinally called once per Task after body completes
    // Also takes the taskLocal
    (taskLocals) =>
    {
       // Any cleanup work on our Task Locals (as you would do in a `finally` scope)
       if (taskLocals.Conn != null)
         taskLocals.Conn.Dispose();

       // Do any reduce / aggregate / synchronisation work.
       // NB : There is contention here!
       Interlocked.Add(ref itemCount, taskLocals.RunningTotal);
    }

more info on msdn

more info on stackOverFlow

This entry was posted in Без рубрики. Bookmark the permalink.