Friday, October 17, 2008

Asynchronious call Delegate

参见 http://blogs.yodersolutions.com/net/?p=17
当我们声明了Delegate 变量(比如FooDelegate), 我们可以使用下面两种方法,来触发这个Delegate,
1. FooDelegate.Invoke(), 或者直接是FooDelegate().
2. FooDelegate.BeginInvoke().
第一种调用方法是同步执行这个delegate.
而第二种方式是异步执行这个delegate, 这个delegate会在另一个线程中被执行, 当前线程将继续执行其它代码. 需要说明的是, 一定要确保这个delegate有机会调用了EndInvoke(), 否则会有资源和内存泄漏.
异步调用的一个简单示例是:
subscriber.BeginInvoke(this, new EventArgs(), Callback, subscriber);
其中第3个参数是回调函数, 它的签名是AsynCallback delegate.当subscriber被执行完后, Callback会被调用.
其中第4个参数一定要是subscriber本身,或者是subscriber本身的一个wrapper, 这样在callback函数体中, 就能访问到subscriber本身来EndInvoke.


class Program
{
static void Main(string[] args)
{
EventPublisher eventPublisher = new EventPublisher();
eventPublisher.FooEvent += new EventHandler(eventPublisher_FooEvent1);
eventPublisher.FooEvent += new EventHandler(eventPublisher_FooEvent2);
Stopwatch sw = new Stopwatch();
sw.Start();
eventPublisher.AsynFireFooEvent();
Console.WriteLine(sw.ElapsedMilliseconds.ToString());
Console.ReadKey();
}

static void eventPublisher_FooEvent1(object sender, EventArgs e)
{
Thread.Sleep(100);
}
static void eventPublisher_FooEvent2(object sender, EventArgs e)
{
Thread.Sleep(200);
}
}



class EventPublisher
{
public event EventHandler FooEvent;


/// <summary>
/// synchronized invoke the all the subscriber services.
/// The process will return until all delegates executions are over.
/// </summary>
public void FireFooEvent()
{
if (FooEvent != null)
FooEvent(this, new EventArgs());
}


/// <summary>
/// Raising events asynchronously lets the event subscribers do their processing in another thread
/// and allows the thread that raised the event to continue processing.
/// </summary>
public void AsynFireFooEvent()
{
if (FooEvent != null)
{
Delegate[] subscribers = FooEvent.GetInvocationList();
foreach (EventHandler subscriber in subscribers)
{
//the 3rd arg should be a AsyncCallback type delegate. When one subscriber service will completed, the AsyncCallback method will be raised.

//the 4th arg should be the exact subscriber or subscriber wrapper, so that in callback function,
// we can access the subcriber to call EndInvoke()
subscriber.BeginInvoke(this, new EventArgs(), Callback, subscriber);
}
}
}



void Callback(IAsyncResult ar)
{
EventHandler raisedEvent = (EventHandler)ar.AsyncState;
raisedEvent.EndInvoke(ar);
}
}