VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > C#教程 >
  • .NET中的异步编程模式 (APM) (二)

Note: 本篇主要内容来自Jeffery Richard的Implementing the CLR Asynchronous Programming Model,看过的同学可以略过。

在前一篇中介绍了使用APM开发多线程程序的有点,同时关于如何使用APM方式的文章也很多了。所以,这篇主要想看看如何使用Jeffery Richard的Power Threading类库,来开发一个支持APM的类。

为什么要自己实现APM

前一篇中,提到了受计算约束(Computing-Bound)与受I/O约束(I/O-Bound)的区别。如果我们是一个受计算约束类型的任务,完全可以将这个方法变成委托(Delegate)的形式,然后通过BeginInvoke/EndInvoke来实现APM;另外,FCL本身也封装了大量对I/O异步操作的类,如FileStream,NetworkStream等,那我们为什么还要自己实现APM呢。Jeffery Richard列举了4个原因:

  1. 尽管FCL提供很多与设备通讯的异步类,但仍有部分未提供,如并口;或者FCL提供的功能不够
  2. 对现有的I/O类库添加功能,如我们在WebHttpRequest可以开发一个HTTP的过滤类等
  3. 实现受计算约束的APM
  4. 对不支持异步模式设备提供异步访问方式

PowerThreading类库中的AsyncResult和AsyncResult<T>

APM的核心就是IAsyncResult接口。当调用类异步方式BeginXxx时,返回IAsyncResult的对象。为了返回满足这个接口的对象,我们的类需要维护的一个 是否完成的状态IsCompleted;一个ManuelResetEvent对象及一个委托保持回调函数。这些虽然比较简单,但很麻烦。使用PowerThreading类库中AsyncResult和AsyncResult<T>,我们可以非常容易的实现支持APM的类。

AsyncResult用于没有返回值,而AsyncResult<T>用于返回类型为T的任务。下面的例子中,我们看看如何使用AsyncResult<T>。

首先,我们准备实现一个能够过滤Stream对象的类,类定义如下:

复制代码
 1 class StreamFilter
 2 {
 3    private Stream                   m_stream;
 4    public StreamFilter(Stream stream)
 5    {
 6    }
 7 
 8    public IAsyncResult BeginParse(
 9             AsyncCallback callback, Object state)
10    {
11    }
12 
13    public Stream Parse()
14    {
15    }
16 
17    public Stream EndParse(IAsyncResult asyncResult)
18    {
19    }
20 }
复制代码

Parse()是同步访问接口,执行主要的任务,而BeginParse()和EndParse()是对应的异步接口。下面是使用AsyncResult<T>后的代码

复制代码
 1 class StreamFilter
 2 {
 3    private Stream                   m_stream;
 4    public StreamFilter(Stream stream)
 5    {
 6       m_stream = stream;
 7    }
 8 
 9    public IAsyncResult BeginParse(
10             AsyncCallback callback, Object state)
11    {
12       //创建一个IAsyncResult对象来标志异步操作
13       AsyncResult<Stream> ar = 
14             new AsyncResult<Stream>(callback, state);
15 
16       // 调用辅助函数,并传递AsycnResult对象
17       // 如果使用Anonymouse Method更简洁
18       ThreadPool.QueueUserWorkItem(ParseHelper,ar);
19 
20       return ar; // 返回IAsyncResult
21    }
22 
23    private void ParseHelper(Object asyncResult)
24    {
25       var ar = (AsyncResult<Stream>)asyncResult;
26       try
27       {
28          // 执行真正的任务
29          Stream result = Parse();
30 
31          // 更新AsycnResult状态
32          ar.SetAsCompleted(result, false);
33       } catch (Exception e)
34       {
35          // 保存Exception对象
36          ar.SetAsCompleted(e, false);
37       }
38    }
39 
40    public Stream Parse()
41    {
42       // 分析m_stream,并返回过滤后的stream对象
43       Stream filterStream = null;
44       return filterStream;
45    }
46 
47    public Stream EndParse(IAsyncResult asyncResult)
48    {
49       var ar = (AsyncResult<Stream>)asyncResult;
50       // 等待任务完成
51       return ar.EndInvoke();
52    }
53 }
复制代码

 

比较重要的是ParseHelper函数,这个函数在新的线程中执行,通过ar.SetAsCompleted来更新状态。 如果结合匿名方法或者Limbda表达式,代码可以变得更加的紧凑。

 

出处:https://www.cnblogs.com/jqwang/p/16587349.html


相关教程