您的位置:首页 > 产品设计 > 产品经理

APM异步编程模型的优势

2012-08-21 14:11 316 查看
我们之所以要花大力气学习APM,就必须要清楚它能解决实际编程中的那些难题。以及现有的技术为什么不行。

简单点说:APM是基于IAsyncResult接口的,采用的BeginXXX和EndXXX的形式来实现异步。

下面这几点就是APM的优势:

1,线程执行是异步的,不会阻塞调用线程。这一点也是我们使用异步的主要目的,我们不就是希望后台处理一些耗时操作吗?

2,任务完成可以得到通知。(非阻塞)

3,任务可以实现进度报告。(需要额外的辅助代码支持)

4,可以有返回值。

5,参数可以是多个。

再看看Thread,ThreadPool,Task能实现上面的几点?这三个中,Task是相对完善的一个,对于第2点它可以通过ContineWith方法来实现,对于第5点,它可以通过Lamda表达式的参数捕获来实现。但总觉得有点怪怪的,没有APM灵活。而对于Thread,ThreadPool来说,除了第1点,其它的都不行。

1,FCL中提供了大量现成的,基于I/O的异步操作实现类。

如,Stream,WebRequest,Dns,SqlCommand等等。对于开发者来说,直接使用它们就可以了。

WebRequest webRequest = WebRequest.Create("http://www.baidu.com");
webRequest.BeginGetResponse(result =>
{
WebResponse webResponse = null;
try
{
webResponse = webRequest.EndGetResponse(result);
using (System.IO.FileStream fs = new System.IO.FileStream("D:baidu.html", System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
using (System.IO.Stream webStream = webResponse.GetResponseStream())
{
webStream.CopyTo(fs);
}
}
}
catch (WebException ex)
{
Console.WriteLine("Failed:" + ex.GetBaseException().Message);
}
finally
{
if (webResponse != null) webResponse.Close();
}
}, null);


2,将IAsyncResutl转成Task来完成。也是上面的代码的不同版本。

这里就是用TaskFactroy的FromAsync方法将IAsyncResutl转成了Task,你肯定觉得这是多余的,但是Task的优势在于它可以有后续Task,可以按顺序执行,在某些场合,这个功能是非常有用的。

WebRequest webRequest = WebRequest.Create("http://www.baidu.com");
TaskFactory factroy = new TaskFactory();
Task<WebResponse> task = factroy.FromAsync<WebResponse>(webRequest.BeginGetResponse, webRequest.EndGetResponse, TaskCreationOptions.None);
task.ContinueWith(t => {
WebResponse webResponse = null;
try
{
webResponse = t.Result;
using (System.IO.FileStream fs = new System.IO.FileStream("D:baidu.html", System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
using (System.IO.Stream webStream = webResponse.GetResponseStream())
{
webStream.CopyTo(fs);
}
}
}
catch (WebException ex)
{
Console.WriteLine("Failed:" + ex.GetBaseException().Message);
}
finally
{
if (webResponse != null) webResponse.Close();
}

});


3,用代理类型(delegate)实现异步调用。

上面的代码都是在调用.Net类库实现的APM类。难道我们有个方法需要异步执行,也需要去包装,实现BeginXXX和EndXXX以及相关的接口吗?如果是这样,如此复杂的APM谁还会用。幸好,代理Delegate天生就支持APM模型。我们申明了一个delegate后,编译器就会自动为我们生成BeginInvoke和EndInvoke等方法。于是乎,我们要做的工作就简单多了,声明一个和方法签名一致的带类类型。调用它的BgeinInvoke方法和EndInvoke方法。就是这么简单!

//假设:这是我们想要异步执行的方法,它有三个参数,和一个自定义类型的返回值
private UserInfo OurFunction(string param1, string param2, string param3)
{
//...
//...
UserInfo uInfo = new UserInfo();
return uInfo;
}
//第一步:定义一个和它签名一致的代理类型
private delegate UserInfo OurFunctionDelegate(string param1, string param2, string param3);

private void MainFunction()
{
//第二步:声明这个代理类型
OurFunctionDelegate hander = new OurFunctionDelegate(OurFunction);
//第三步:调用BgeinInvoke方法,同时传入一个回调函数
hander.BeginInvoke("p1", "p2", "p3", AsyncCallBack, hander);
}
//第四步:定义一个回调函数
private void AsyncCallBack(IAsyncResult result)
{
OurFunctionDelegate hander = (OurFunctionDelegate)result.AsyncState;

try
{
//函数异步执行完成,会进入这个函数,调用EndInvoke方法可以得到结果,如有异常,也会在这里抛出
UserInfo info = hander.EndInvoke(result);
}
catch (Exception)
{
//处理异步操作的异常,当然,这里的异常应该是ArrgregateException。
}
}


注意事项:对于异步调用获取结果的方式,主要有以下几种。

1,利用AsyncCallBack回调函数,它是不阻塞的。(首选)

2,利用IAsyncResult的Result。调用线程遇到这句话会阻塞。

3,利用IAsyncResult的AsyncWaitHandle.WaitOne()。和2一样会阻塞。

4,轮询IAsyncResult的IsCompleted属性。同样会耗CPU资源,阻塞调用线程,如新开一个线程来轮询又浪费线程资源。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: