您的位置:首页 > 编程语言

异步编程设计模式的一些体会

2009-08-30 23:17 288 查看
学习异步编程过程中的一些体会,高手可以自动过滤了。
一般,在执行运行时间比较长的操作,如规模比较大的计算(n皇后问题,n>20),打开大文件,图像处理等,系统因等待操作执行而无法响应其他操作,处于一种“假死”状态,给用户非常不好的体验。因此,我们希望将这样操作提交到后台执行。一种比较简易的思路就是将以上提到同步操作改为异步调用方式。关于使用委托异步调用方法,msdn上的文章做了很多好的总结,它将使用AsyncCallback 委托调用异步方法的总结为4种情况:
1、通过结束异步操作来阻止应用程序执行。
2、使用 AsyncWaitHandle 阻止应用程序的执行。
3、轮询异步操作的状态。
4、使用 AsyncCallback 委托结束异步操作。
我们可以在msdn上检索到这几篇文章,通过baidu,google也可以很方便的找到。
这里我主要想讲讲学习的一些体会。
1、通过结束异步操作来阻止应用程序执行。其效果跟直接执行同步方法差不多。我觉得可以忽略不计了。
2、使用AsyncWaitHandle阻止应用程序执行。执行效果跟1差不多,但阻塞调用线程的思路不同。我们查看EndInvoke方法的帮助,有一条备注“如果尚未完成异步操作,此函数将阻止,直至结果可用。”,也就是说1方法是利用结束异步操作方法EndInvoke来阻止执行线程的。而2方法,是通过等待事件挂起执行线程的,这个等待事件是IAsyncResult的一个属性,叫AsyncWaitHandle。一般的调用语句如下:
IAsyncResult ar=caller.BeginInvoke(…);
ar.AsyncWaitHandle.WaitOne();
caller.EndInovke(ar);
AsyncWaitHandle阻止线程,直到当操作方法执行完毕,设置信号才结束等待,恢复线程的执行。与1相比较,因为用了WaitHandle,可以设置过期时间,但是因为最终都是要执行EndInvoke方法,即使因为超期退出等待,也会被EndInvoke阻塞。所以从执行效果看,1、2的区别不大。
3、IAnsyncResult用于监视异步执行过程,它的IsCompleted属性,表示异步过程是否执行完毕,因此我们可以轮询该属性,以判断执行是否完成。那么也可以同过while(!ar.IsCompleted){}来阻塞当前线程。与前两种方法相比,我们可以在异步执行过程中完成其他操作。如,可以在轮询过程中,设置一个processbar,提示操作正在进行。也可以在while循环中加入Thread.sleep(1000)调用释放控制权,这样系统有机会处理其他事件请求,”假死“的感觉没有那么强烈。
4、使用AsyncCallback应该是最好的方式了。其本质是由BeginInvoke方法开辟一个线程执行操作,并在操作完成时执行回调方法。因此我们需要在回调方法中执行EndInvoke。相比其他3种方法,本方法是最复杂的。我个人觉得有几个地方要注意下:
(1)怎样在回调函数中获得执行方法的签名,以调用EndInvoke方法
可以有两种方式,看下面的例子
class clsAnsyc
{
public void dosomething() //同步方法
{
Thread.Sleep(30000); //休眠30秒
System.Windows.Forms.MessageBox.Show("ok");
}
}
public delegate void AsyncCall(); //委托
private void CallBack(IAsyncResult result) //回调函数
{
AsyncCall caller = (AsyncCall)result.AsyncState;
caller.EndInvoke(result);
}
private void button4_Click(object sender, EventArgs e)
{
clsAnsyc demo = new clsAnsyc();
AsyncCall caller = new AsyncCall(demo.dosomething);
IAsyncResult ar = caller.BeginInvoke(new AsyncCallback(this.CallBack), caller);
//传递一个回调方法new AsyncCallback(this.CallBack), 传递委托到ar.AsyncState属性
}
从上面代码我们可以看到,通过传递caller到IAsyncResult的AsyncState属性,可以完成对Caller的EndInvoke方法的调用。
另外我们还可以使用AsyncCall类,它可以直接由IAsyncReult接口强制转换得到。该类有一个AsyncDelegate成员,可获取在其上调用异步调用的委托对象。使用该类需要引入命名空间System.Runtime.Remoting.Messaging
代码修改如下:
添加
using System.Runtime.Remoting.Messaging;
private void button4_Click(object sender, EventArgs e)
{
clsAnsyc demo = new clsAnsyc();
AsyncCall caller = new AsyncCall(demo.dosomething);
IAsyncResult ar = caller.BeginInvoke(new AsyncCallback(this.CallBack), null);
}
private void CallBack(IAsyncResult result)
{
AsyncResult ar = (AsyncResult)result;
AsyncCall caller =(AsyncCall) ar.AsyncDelegate;
caller.EndInvoke(result);
}
(2)怎么取到异步调用的执行结果
以后再讨论,今天就写到这里。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: