We would like to build a pattern around certain loops in our solution, that will allow them to run in serial, or parallel, depending on factors. Below is the general form of it.
Since the concurrent collections dont share a common interface with the regular collections, we need some sort of adapter to write general code.
Specifically around the usage of the addFunc delegate in the loop body, is there anything there that would end up causing problems in the long term that we might miss? It runs fine as of now, but....?
Action<SomeType> addFunc;
if(runInParallel)
{
addFunc = concurrentBag.Add;
loopDelegate = Parallel.ForEach;
}
else
{
addFunc = iList.Add;
loopDelegate = Serial.ForEach; // wrapper delegate for foreach
}
loopDelegate(source, item =>
{
SomeType result = longRunningTask(item);
...
addFunc(result); // will this
});
Curious why not use TPL in .NET 4.0? http://msdn.microsoft.com/en-us/library/dd537609.aspx
There is an excellent white paper of the considerations they have taken when developing TPL, if you can't use .NET 4, you should look at the paper and consider some of the gotcha's in there.
Updated based on comment pointing out the obvious.
I'd use some syntactic sugar like,
ForEach<Tsource>(Predicate<IEnumerable<TSource>> isParallel, IEnumerable<TSource> source, Action<TSource> body)
{
if(isParallel(source))
{
Parallel.ForEach<TSource>(source, body);
}
else
{
foreach (TSource element in source)
{
body(element);
}
}
}
There are two main advantages over your implementation.
This is the paper I was referring to btw, http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=19222.
It's all a very good read if you're imeplemeting this, but pay particular attention to, Pages 1[5-7], 26, 3[0-2].
The syntactic sugar means you can call it as you would with TPL,
MyParllelLibrary.ForEach( (list) => true, list), item =>
{
// What my code does
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With