C# 4.0 Using Parallel.Invoke to execute arbitrary number of operations in parallel

By Indranil Chatterjee

The Parallel class provides methods like For or ForEach to allow execution of a common set of operations on all items of a sequence in parallel. But not all multi threading scenarios involve operating on sequences. For cases where we need to execute arbitrary set of operations (even totally unrelated to each other) in parallel, Parallel.Invoke (or its overload) comes in handy. This is an example to show that.

In a couple of previous posts, I explained how to use LINQ to get the longest word from a text and how to get the number of repititions of a single word within a text.  The following program combines the two, executes them both sequentially and parallelly and dumps the results (and elapsed time) for both options:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Drawing;
using System.Diagnostics;

namespace ParallelProgramming.TaskPrograms
{
//The program then manipulates the images by using a sequential and a parallel loop and displays both results
//which you can compare

class Program
{
static void Main(string[] args)
{
var words = GetWords();
ExecuteSequentially(words);
ExecuteParallelly(words);
}

static void ExecuteSequentially(IEnumerable<string> words)
{
var watch = Stopwatch.StartNew();
GetLongestWord(words);
GetCountForWord(words, "Processing");
watch.Stop();
Console.WriteLine("Sequential operations executed in {0} milliseconds", watch.ElapsedMilliseconds);
}

static void ExecuteParallelly(IEnumerable<string> words)
{
var watch = Stopwatch.StartNew();
Parallel.Invoke
(
() => GetLongestWord(words),
() => GetCountForWord(words, "Processing")
);
watch.Stop();
Console.WriteLine("Parallel operations executed in {0} milliseconds", watch.ElapsedMilliseconds);
}

static IEnumerable<string> GetWords()
{
var text = "This is a paragraph which needs to be analyzed for word processing. " +
"The term processing includes searching for most repeated words, the longest word in this "

+
"text phrase and to find the number of times a given word is repeated in this text.";
return text.Split(
new char[] { ' ', '\u000A', ',', '.', ';', ':', '-', '_', '/' },
StringSplitOptions.RemoveEmptyEntries);
}

private static string GetLongestWord(IEnumerable<string> words)
{
var longestWord = words.OrderByDescending(w => w.Length).First();

Console.WriteLine("The longest word is '{0}'.", longestWord);
return longestWord;
}

private static void GetCountForWord(IEnumerable<string> words, string term)
{
var findWord = words.Where(w => w.ToUpper().Contains(term.ToUpper()));

Console.WriteLine("The word '{0}' occurs {1} times.",
term, findWord.Count());
}
}
}

Parallel.Invoke takes in an array of Action delegates. Its signature looks like:
public static void Invoke( params Action[] actions) //There is another overload that takes in a ParallelOptions

argument.

It executes each of these Action delegates, "potentially" as parallel tasks to take advantage of multiple cores/processors.

Please note the word potentially. What this means is, with the Parallel.Invoke method above, there's no gurantee that these

operations will be executed in parallel. The underlying task scheduler decides (based on its own extensible algorithm) how

to schedule the tasks, on how many threads or whether to parallelize at all. It bases it decision on factors like the

expensiveness of each operation, number of available cores, CPU cycles and others. For example, the program above, on my

machine, produced the following results in one run:

---------------------------------------------------------
The longest word is 'processing'.
The word 'Processing' occurs 2 times.
Sequential operations executed in 17 milliseconds
The longest word is 'processing'.
The word 'Processing' occurs 2 times.
Parallel operations executed in 3 milliseconds

When I tried the same program, but this time around with two operations that calculates the sum and maximum value from a

given set of 10000 integers, both produced 3 milliseconds.

The other overload of Paralle.Invoke takes an ParallelOptions argument using which one can pass on a cancellation token,

control the degree of parallellism or even pass a custom Task schedulerto be used for scheduling the parallel operations.

C# 4.0 Using Parallel.Invoke to execute arbitrary number of operations in parallel  (1529 Views)