During devweek 2009 Oliver introduced me to Fluent Api's, I personally love programs that naturally read, after all programs are read far more often than written. This week a posting on the Parallel Extensions blog demonstrated how to achieve parallel while, since we only have Parallel.For and Parallel.ForEach
static void Main(string[] args)
{
ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
for (int i = 0; i < 10; i++)
{
queue.Enqueue(i);
}
Action<ParallelLoopState> processQueue = (lps) =>
{
int item;
if (queue.TryDequeue(out item))
{
Console.WriteLine(" Thread Id = {0} Task Id = {1} : {2}", Thread.CurrentThread.ManagedThreadId, Task.Current.Id, item);
}
};
Func<bool> queueContainsItems = () => queue.IsEmpty == false;
ParallelUtil.While(new ParallelOptions(), queueContainsItems, processQueue);
}
I thought I’d combine both these ideas and produce what I would consider a more Fluent version
public static class ParallelUtil
{
private static IEnumerable<bool> Infinite()
{
while (true) yield return true;
}
private static ParallelOptions NoParallelOptions = new ParallelOptions();
public static void InParallelWhile(this Action<ParallelLoopState> action, Func<bool> condition, ParallelOptions options = null)
{
if (options == null) options = NoParallelOptions;
Parallel.ForEach(IterateForever(), options ,
(ignored, loopState) =>
{
if (!condition())
{
loopState.Stop();
}
else
{
action(loopState);
}
});
}
private static IEnumerable<bool> IterateForever()
{
while (true)
{
yield return true;
}
}
}
class Program
{
static void Main(string[] args)
{
ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
for (int i = 0; i < 10; i++)
{
queue.Enqueue(i);
}
Action<ParallelLoopState> processQueue = (lps) =>
{
int item;
if (queue.TryDequeue(out item))
{
Console.WriteLine(" Thread Id = {0} Task Id = {1} : {2}", Thread.CurrentThread.ManagedThreadId, Task.Current.Id, item);
}
};
Func<bool> queueContainsItems = () => queue.IsEmpty == false;
processQueue.InParallelWhile(queueContainsItems);
}
}
}
The key difference is the first example you use the following line to process the queue in parallel
ParallelUtil.While(new ParallelOptions(), queueContainsItems, processQueue);
As opposed to the second version with a perhaps more fluent implementation
processQueue.InParallelWhile(queueContainsItems);