I had introduced a while back a ParallelMap function, and then later I updated it to make sure that it was tracking order when results were returned. I took a look at the method recently, and realized that it was ugly. I had introduced a struct that allowed me to tie the index to the result value, not really realizing that I could have done it all with closures. I guess that is the normal path of code though… write…rewrite…come back 3 months later…rewrite. Well, anyways, in my last post I mentioned a few updates that I had made to the method and promised to post it. So, here it is:
public static IEnumerable<TResult> ParallelMap<TArg, TResult>(
this IEnumerable<TArg> list,
Func<TArg, TResult> func)
var result = new TResult[list.Count()];
using (var resetEvent = new ManualResetEvent(false))
int count = result.Length;
int i = 0;
foreach (TArg item in list)
TArg localItem = item;
int index = i;
TResult value = func(localItem);
result[index] = value;
if (Interlocked.Decrement(ref count) == 0)
Beautiful! I am still using the ThreadPool class, I am going to implement a custom version in the future that will use explicit threads. The changes I have made is that we are now copying the item and index to a local variable and then using them in the lambda that we are now passing directly into the QueueUserWorkItem method. So, now we can drop our struct that we were before passing as state.
I hope that someone out there finds this method useful!
Loved the article? Hated it? Didn’t even read it?
We’d love to hear from you.