Because the TPL backport not only contains Parallel.* but also PLINQ, concurrent collections, etc, I will try to use this one.
Just for fun, I profiled both the TPL implementation and my own, in the very basic and naive test, mine was actually a little bit faster.
Microsoft TPL backport: 00:00:17.0673098
My Implementation: 00:00:16.9210535
Intel Q6600 (quad-core), 4GB of RAM, Win8.1(x64), VS2013 targetting .NET 3.5
The code is here (github gist), the colorful output of the Concurrency Visualizer is below:
This negligeable performance difference (in the best case) gets outweight by the many optimisations the .NET team put in for special cases.
Question:
To ease working with multithreaded code, I wanted to implement a version of Parallel.ForEach
for .NET 3.5.
We are for the moment stuck with 3.5 and cannot upgrade. We cannot use external libraries like TPL.
I found this via Google, but this threw sporadic exceptions during runtime, and because I couldn't find another Version I decided to roll my own.
I did of course test it, but i am always a bit cautious with multithreaded code.
public class Parallel
{
public static void ForEach<T>(IEnumerable<T> items, Action<T> action)
{
if (items == null)
throw new ArgumentNullException("enumerable");
if (action == null)
throw new ArgumentNullException("action");
var resetEvents = new List<ManualResetEvent>();
foreach (var item in items)
{
var evt = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem((i) =>
{
action((T)i);
evt.Set();
}, item);
resetEvents.Add(evt);
}
foreach (var re in resetEvents)
re.WaitOne();
}
}
WaitHandle.WaitAll(resetEvents.ToArray())
. See WaitHandle.WaitAll. It even lets you provide a timeout if you need to support actions which could never terminate. \$\endgroup\$