Asynchronous Programming Model

 

整个异步调用过程中都是围绕IAsyncResult来进行的,大家可以看看上篇文章的例子,BeginXXX 返回这个对象,EndXXX接收这个对象来结束当前异步对象,下面我们来看看IAsyncResult 接口成员/和实现此接口的AsyncResult成员(其中有些在上篇中已经涉及到)

IAsyncResult接口

1转:异步的核心: IAsyncResultpublic interface IAsyncResult
2    }

AsyncResult

 1转:异步的核心: IAsyncResult    public class AsyncResult : IAsyncResult, IMessageSink
 2    }

 

注意:基本上都是只读属性

下面我们来看看异步的执行顺序,并回顾下 IAsyncResult 下各个属性的应用,如果还是不熟悉请看前2篇文章.

Code 1:

 1转:异步的核心: IAsyncResult   class Program
 2
(MyThirdAsyncCode.AsyncTest.SalaryEventHandler)obj.AsyncDelegate;
32转:异步的核心: IAsyncResult
33转:异步的核心: IAsyncResult            if (asyncResult.IsCompleted)// 判读是否已经调用完成
34转:异步的核心: IAsyncResult                Console.WriteLine("[(#{1}){0}]:Asynchronous Finished.", DateTime.Now.ToString(), Thread.CurrentThread.ManagedThreadId);
35转:异步的核心: IAsyncResult
36转:异步的核心: IAsyncResult            decimal val = del.EndInvoke(asyncResult);
37转:异步的核心: IAsyncResult
38转:异步的核心: IAsyncResult            Console.WriteLine("[(#{2}){0}]:Output Result:{1}", DateTime.Now.ToString(), val + para, Thread.CurrentThread.ManagedThreadId);
39转:异步的核心: IAsyncResult        }
40转:异步的核心: IAsyncResult    }
41转:异步的核心: IAsyncResult
42转:异步的核心: IAsyncResult    public class AsyncTest
43    }


转:异步的核心: IAsyncResult
1

我们看到DoAntherJob 比异步YearlySalary2,看代码中(1)(2),两个线程的执行结果

接下来,我们说说AsyncWaitHandle 属性. 他返回WaitHandle对象(System.Threading.WaitHandle), 他有3个重要的方法. WaitOne / WaitAny / WaitAll ,我们先来说下WaitOne,Code1代码基础上只是增加了下面红色部分.

1,WaitOne

Code 1.1

IAsyncResult ar = del.BeginInvoke(100000, 15, 100000, callback, 2000);
//
阻碍当前线程,直到异步调用结束.
ar.AsyncWaitHandle.WaitOne();

//
开始其他工作.
DoAntherJob();

转:异步的核心: IAsyncResult
1.1

执行输出,对比图1我们可以看到执行的次序不一样了(看时间),调用WaitOne,会阻碍当前线程,直到异步完成,才释放当前的线程, WaitOne 提供了时间的重载版本WaitOne(int millisecondsTimeout)/ WaitOne(TimeSpan timeout);来判断阻碍的时间.无参的版本是无限等待的(直到异步调用结束)

2, WaitAll

我们在Code1的代码基础上加上Hello的异步调用(使Main提供多个异步调用),注意红色部分.

Code 1.2

 1转:异步的核心: IAsyncResult    class Program
 2
(MyThirdAsyncCode.AsyncTest.SalaryEventHandler)obj.AsyncDelegate;
32转:异步的核心: IAsyncResult
33转:异步的核心: IAsyncResult            if (asyncResult.IsCompleted)// 判读是否已经调用完成
34转:异步的核心: IAsyncResult                Console.WriteLine("[(#{1}){0}]:Asynchronous Finished.", DateTime.Now.ToString(), Thread.CurrentThread.ManagedThreadId);
35转:异步的核心: IAsyncResult
36转:异步的核心: IAsyncResult            decimal val = del.EndInvoke(asyncResult);
37转:异步的核心: IAsyncResult            Console.WriteLine("[(#{2}){0}]:Output Result:{1}", DateTime.Now.ToString(), val, Thread.CurrentThread.ManagedThreadId);
38转:异步的核心: IAsyncResult        }
39转:异步的核心: IAsyncResult
40转:异步的核心: IAsyncResult        static void OnHelloCallback(IAsyncResult asyncResult)
41
(MyThirdAsyncCode.AsyncTest.AsyncEventHandler)obj.AsyncDelegate;
45转:异步的核心: IAsyncResult
46转:异步的核心: IAsyncResult            if (asyncResult.IsCompleted)// 判读是否已经调用完成
47转:异步的核心: IAsyncResult                Console.WriteLine("[(#{1}){0}]:Asynchronous Finished.", DateTime.Now.ToString(), Thread.CurrentThread.ManagedThreadId);
48转:异步的核心: IAsyncResult
49转:异步的核心: IAsyncResult            string val = del.EndInvoke(asyncResult);
50转:异步的核心: IAsyncResult            Console.WriteLine("[(#{2}){0}]:Output Result:{1}", DateTime.Now.ToString(), val, Thread.CurrentThread.ManagedThreadId);
51转:异步的核心: IAsyncResult        }
52转:异步的核心: IAsyncResult    }
53转:异步的核心: IAsyncResult
54转:异步的核心: IAsyncResult    public class AsyncTest
55    }


转:异步的核心: IAsyncResult
1.2

从图1.2中可以看出,WaitAll会阻碍当前线程(主线程#10),等待所有异步的对象都执行完毕(耗时最长的异步),才释放当前的线程,WaitAll/WaitAny的重载版本和WaitOne一样.

3, WaitAny

WaitAll 基本上是一样的.我们可以使用 WaitAny 来指定某个/某几个委托先等待,修改Code1.2红色部分,使用WaitAny.

Code1.3
//
salayAsyc异步的句柄保存到WaitHandle 对象中
WaitHandle
[] handles = { salayAsyc.AsyncWaitHandle };
//
阻碍当前线程,直到所有异步调用结束.
WaitHandle
.WaitAny(handles);

转:异步的核心: IAsyncResult

1.3

我们阻碍了DoAntherJob(#10)线程,直到Salary异步调用计算完成.同样我们可以巧用这三个方法来改变我们方法执行的顺序.


释放资源

Code2

1转:异步的核心: IAsyncResultstatic void OnSalaryCallback(IAsyncResult asyncResult)
2
(MyThirdAsyncCode.AsyncTest.SalaryEventHandler)obj.AsyncDelegate;
6转:异步的核心: IAsyncResult
7转:异步的核心: IAsyncResult            decimal val = del.EndInvoke(asyncResult);
8转:异步的核心: IAsyncResult            asyncResult.AsyncWaitHandle.Close();//显示的释放资源
9转:异步的核心: IAsyncResult        }


当开始调用BeginXXX,就会创建一个新的AsyncResult对象.这个对象会构造一个WaitHandle句柄(通过AsyncWaitHandle访问),当我们EndXXX,并不会马上关闭这个句柄,而是等待垃圾收集器来关闭,这时候我们最后在调用EndXXX完成后,显示的关闭这个句柄.

 

说到这里,我们基本上把异步方法都解释一遍,下面我们来看看重构的异步对象,我们也可以细细体会异步对象的内部执行代码..下面Code3.1/3.2/3.3代码来自Jeffery Richard大师的Power Threading类库,具体可查看http://msdn.microsoft.com/en-us/magazine/cc163467.aspx

 

1,构造一个内部无参的AsyncResultNoResult对象,继承IAsyncResult接口(保留原创的注释)

Code3.1

  1转:异步的核心: IAsyncResult internal class AsyncResultNoResult : IAsyncResult
  2    }

 

2,继承AsyncResultNoResult对象,并且为他提供返回值和泛型的访问

Code3.2

 1转:异步的核心: IAsyncResultinternal class AsyncResult<TResult> : AsyncResultNoResult
 2    }


3,模拟长时间的异步工作

Code3.3

 1转:异步的核心: IAsyncResultinternal sealed class LongTask
 2    }


来自
Jeffrey Richter大师更多更详细的异步操作方法, 请查看http://www.wintellect.com/PowerThreading.aspx,对于一些朋友可能看不懂Code3.1-3.3代码(其实没什么所谓的),因为涉及到过多的线程知识,这里出于让你获得更多的更深层次的(异步)认识为目的,才提供上面代码.

相关文章:

  • 2021-10-20
  • 2022-12-23
  • 2022-01-26
  • 2021-06-28
  • 2022-12-23
猜你喜欢
  • 2021-09-27
  • 2022-01-31
  • 2022-02-28
  • 2021-12-11
  • 2022-02-08
相关资源
相似解决方案