![]() |
Languages »
C# »
Delegates and Events
Intermediate
License: The Code Project Open License (CPOL)
Action ExtensionsByleppieParallelization of multicast delegates |
C# (C# 3.0), Windows, Dev
|
|
Advanced Search |
|
|
|
||||||||||||||||
Ennis Ray Lynch, Jr. gave me an idea the other day in the Lounge. The basic idea was running multicast delegates in parallel.
The code to run delegates in parallel is rather trivial.
static void Run(Action[] aa)
{
List<IAsyncResult> waits = new List<IAsyncResult>();
foreach (Action a in aa)
{
waits.Add(a.BeginInvoke(null, null));
}
foreach (IAsyncResult ar in waits)
{
ar.AsyncWaitHandle.WaitOne();
}
}
To run a multicast delegate in parallel follows the same pattern.
static void Run(Action t)
{
List<IAsyncResult> waits = new List<IAsyncResult>();
foreach (Action a in t.GetInvocationList())
{
waits.Add(a.BeginInvoke(null, null));
}
foreach (IAsyncResult ar in waits)
{
ar.AsyncWaitHandle.WaitOne();
}
}
Following the above pattern, we simply create stubs for the generic Action delegate (only 1 shown for clarity). If needed, you can replace with your own delegate type. There is one important aspect to keep in mind; the delegate MUST return void. Why, you may ask? The answer is simple. There is no easy way to consume multiple return values in C#.
static class ActionExtensions
{
class WaitList : IDisposable
{
readonly List<IAsyncResult> waits = new List<IAsyncResult>();
public void Add(IAsyncResult ar)
{
waits.Add(ar);
}
public void Dispose()
{
foreach (var ar in waits)
{
ar.AsyncWaitHandle.WaitOne();
}
}
}
public static Action MakeParallel(this Action t)
{
return () =>
{
using (var w = new WaitList())
{
foreach (Action a in t.GetInvocationList())
{
w.Add(a.BeginInvoke(null, null));
}
}
};
}
}
The usage is also trivial. Simply call the MakeParallel extension method.
class Program
{
static void Main(string[] args)
{
Action<int> f = null;
for (int i = 0; i < 8; i++)
{
f += Thread.Sleep;
}
Stopwatch ws = Stopwatch.StartNew();
f(250);
Console.WriteLine("ser: {0:f3}", ws.Elapsed.TotalMilliseconds);
f = f.MakeParallel();
ws = Stopwatch.StartNew();
f(250);
Console.WriteLine("par: {0:f3}", ws.Elapsed.TotalMilliseconds);
Console.ReadLine();
}
}
The output should show the parallel version running at half (or quarter) the time of the serial version.
From what I can determine, BeginInvoke utilizes the number of logical CPUs. I have however not been able to test this.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 1 Jul 2008 Editor: Deeksha Shenoy |
Copyright 2008 by leppieEverything else Copyright © CodeProject, 1999-2009 Web15 | Advertise on the Code Project |