In the post Parallelizing Work With C# & .NET we discussed using Parallel.ForEach to process Tasks in parallel and consume their results.

Occasionally, the problem is that you are required to process several tasks, neither of which returns results. One opportunity for improvement is running these in parallel.

This is an opportunity to use Parallel.Invoke.

Let us take for example the following example, a task that processes spies given their names:

void ProcessSpy(string name)
{
    Log.Information("Starting to Process {Name} ...", name);
    Thread.Sleep(TimeSpan.FromSeconds(25));
    Log.Information("Completed Processing {Name} ...", name);
}

Our initial program can look like this:

Log.Logger = new LoggerConfiguration()
    .Enrich.WithThreadId()
    .WriteTo.Console(
        outputTemplate:
        "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3} Thread:{ThreadId}] {Message:lj}{NewLine}{Exception}")
    .CreateLogger();

// Process James Bond
ProcessSpy("James Bond");
// Process Vesper Lynd
ProcessSpy("Verpser Lynd");
// Process Eve Moneypeny
ProcessSpy("Eve Moneypeny");
// Process Q
ProcessSpy("Q");
// Process M
ProcessSpy("M");

Running this program will produce the following:

ParallelForEach1

We can see here that this program has taken over three minutes to run, as each task is run sequentially.

We can improve this to run in parallel like so:

Parallel.Invoke(
    () => ProcessSpy("James Bond"),
    () => ProcessSpy("Vesper Lynd"),
    () => ProcessSpy("Eve Moneypenny"),
    () => ProcessSpy("Q"),
    () => ProcessSpy("M")
);

This will return the following:

ParallelInvoke2

We can see here that the program now takes 30 seconds, because all the tasks are run in parallel.

TLDR

Parallel.Invoke allows tasks that do not return anything (Actions) to be run in parallel.

The code is in my GitHub.

Happy hacking!