Asynchronous Result 模式
2009-12-23 21:21 飞逝心情 阅读(237) 评论(0) 编辑 收藏 举报异步结果模式提供了一种不必显式的调用Thread类来编写线程方法代码,而是使用委托实例的方式实现多线程处理的一种方法.
先来见识一下这种方法的标准代码:
public class AsyncResultPatternIntroduction { delegate void WorkerThreadHandler(); public static AutoResetEvent ResetEvent = new AutoResetEvent(false); public static void Main() { Console.WriteLine("Application started...."); WorkerThreadHandler workerMethod = null; IAsyncResult asyncResult = null; try { workerMethod = new WorkerThreadHandler(DoWork); Console.WriteLine("Starting thread...."); //执行操作,将结果保存在asyncResult中 asyncResult = workerMethod.BeginInvoke(null, null); // Display periods as progress bar. //间隔一段时间,查看线程是否结束,此循环在异步方结束 while (!asyncResult.AsyncWaitHandle.WaitOne(100, false)) { Console.Write('.'); } Console.WriteLine(); Console.WriteLine("Thread ending...."); } finally { //确保异步线程的调用结束 if (workerMethod != null && asyncResult != null) { workerMethod.EndInvoke(asyncResult); } } Console.WriteLine("Application shutting down...."); } public static void DoWork() { //模仿一个需要长时间的操作 Console.WriteLine("\nDoWork() started...."); Thread.Sleep(6000); Console.WriteLine("\nDoWork() ending...."); } }
上面的方法很好的做到了异步,但是,你没有办法来做到另外的一点,就是传入数据,做数据的交换。那么,含有参数的情况下怎么处理呢?假设我们有一个方法。
public static string[] GetFiles( string searchPattern, bool recurseSubdirectories) { //do action... // }
这个方法有两个参数,返回一个数组。为了传入参数,我们需要定义一个新的委托。
delegate string[] GetFilesHandler( string searchPattern, bool recurseSubdirectories);
有了这个委托后,我们可以按照上面的方法一样,声明一个实例,然后调用BeginInvoke()方法。不过需要注意的是这时候的BeginInvoke()方法需要传入四个参数。
result = asyncGetFilesHandler.BeginInvoke( searchPattern, recurseSubdirectories, null, null);
很简单的,前面的两个参数直接被传到方法中。
与BeginInove() 类似,由于我们的方法返回了值,在调用EndInove()方法时,可以获得方法的返回时。
// Retrieve the results files = (string[])asyncGetFilesHandler.EndInvoke(result);
注意,如果方法的名称标记为ref,或者out,则ref 参数和out 参数也应该存在于EndInvoke()的参数列表中
除了轮询,我们还可以采用通知机制,让它能在一个线程完成之后触发一个事件,这就是AsycCallBack模式,它会在方法结束后立即调用回调委托。
假设我们有一个方法名称叫SearchComplete,它用于处理当搜索文件结束时的操作。
public static void SearchCompleted() { //Write SearchedResult! }
如果我们想要在搜索完成时就要执行这个方法,我们就可以在BeginInvoke()方法的倒数第二个参数中传递要执行的函数。注意,此时被调和的参数需要包含参数列表。
public static void SearchCompleted(IAsyncResult result)而我们的方法调用如下所示.
asyncGetFilesHandler.BeginInvoke(
arg, recurseSubdirectories,
SearchCompleted, null);
由于BeginInvoke方法的最后一个参数可传入方法的参数,因此,如果要向被调用的函数传入方法参数,则可以放到BeginInvoke()方法的最后一个参数中。由于是object因此,可以传递任意的类型。
传入的参数可以在调用方法时,以下面的方法取出来。
string searchPattern = (string)result.AsyncState;
一般来说,我们需要在回调函数中调用EndInvoke()方法,而不是放在Main()中,这是因为在调用EndInvoke()方法时会暂时阻止,直到异步调用完成,而在回调内则不存在这样的问题。这里是完善后的回调方法。分别实现了上面提到的几个功能。
public static void SearchCompleted(IAsyncResult result) { string searchPattern = (string)result.AsyncState; Console.WriteLine("{0}:", searchPattern); AsyncResult asyncResult = (AsyncResult)result; GetFilesHandler handler = (GetFilesHandler)asyncResult.AsyncDelegate; string[] files = handler.EndInvoke(result); foreach (string file in files) { Console.WriteLine("\t" + Path.GetFileName(file)); } }
Asynchronous Result模式的一个关键特性是:调用者决定是否异步调用一个方法。被调用的对象可以选择提供异步方法,也可以在内部继续使用Asynchronous Result模式.被调用方法实现异步API的一个前提是被调用的类可以比调用者更为有效的实现异步功能,或者已经方法执行起来相当的慢。