异步编程(AsyncCallback委托,IAsyncResult接口,BeginInvoke方法,EndInvoke方法)

异步编程(AsyncCallback委托,IAsyncResult接口,BeginInvoke方法,EndInvoke方法)
异步编程(AsyncCallback委托,IAsyncResult接口,BeginInvoke方法,EndInvoke方法)

让我们来看看同步异步的区别:

同步方法调用在程序继续执行之前需要等待同步方法执行完毕返回结果

异步方法则在被调用之后立即返回以便程序在被调用方法完成其任务的同时执行其它操作

.NET框架基类库中有好几种类都可以提供同步和异步的方法调用。

因为同步方法调用会导致程序流程中途等待,所以采用同步方法的情况下往往会导致程序执行的延迟

相比来说,在某些条件下选择异步方法调用就可能更好一些

例如,有的时候程序需要给多个Web服务发出请求,还有远程处理信道(HTTP、TCP)和代理,这时就最好采用异步方法

.NET Framework允许异步调用任何方法,定义与需要调用的方法具有相同签名的委托

CLR将自动为该委托定义添加适当签名的BeginInvoke虚方法和EndInvoke虚方法和Invoke 方法。

关于委托的这3个方法的详细说明可以参考这文章

https://www.360docs.net/doc/218933794.html,/aierong/archive/2005/05/25/162181.html

我们先来了解这2个方法和一个委托和一个接口:

(1)

BeginInvoke 方法可启动异步调用。

它与您需要异步执行的方法具有相同的参数,另外它还有两个可选参数。第一个参数是一个AsyncCallback 委托,该委托引用在异步调用完成时要调用的方法。第二个参数是一个用户定义的对象,该对象可向回调方法传递信息。BeginInvoke 立即返回,不等待异步调用完成。BeginInvoke 会返回IAsyncResult,这个结果可用于监视异步调用进度。

结果对象IAsyncResult是从开始操作返回的,并且可用于获取有关异步开始操作是否已完成的状态。

结果对象被传递到结束操作,该操作返回调用的最终返回值。

在开始操作中可以提供可选的回调。如果提供回调,在调用结束后,将调用该回调;并且回调中的代码可以调用结束操作。

(2)

EndInvoke 方法检索异步调用的结果。

调用BeginInvoke 后可随时调用EndInvoke 方法;如果异步调用尚未完成,EndInvoke 将一直阻止调用线程,直到异步调用完成后才允许调用线程执行。EndInvoke 的参数包括您需要异步执行的方法的out 和ref 参数以及由BeginInvoke 返回的IAsyncResult。

(3)

AsyncCallback委托用于指定在开始操作完成后应被调用的方法

AsyncCallback委托被作为开始操作上的第二个到最后一个参数传递

代码原型如下:

[Serializable]

public delegate void AsyncCallback(IAsyncResult ar);

AsyncCallback为客户端应用程序提供完成异步操作的方法。开始异步操作时,该回调委托被提供给客户端。AsyncCallback 引用的事件处理程序包含完成客户端异步任务的程序逻辑。

AsyncCallback 使用IAsyncResult 接口获取异步操作的状态。

(4)

IAsyncResult接口

它表示异步操作的状态.

该接口定义了4个公用属性

代码原型如下:

public interface IAsyncResult

实际上,发起和完成.NET异步调用有4种方案可供你选择

1.方案1-使用EndInvoke等待异步调用

异步执行方法最简单的方式是通过调用委托的BeginInvoke 方法来开始执行方法,在主线程上执行一些工作,然后调用委托的EndInvoke 方法。EndInvoke 可能会阻止调用线程,因为它直到异步调用完成之后才返回。这种技术非常适合文件或网络操作,但是由于EndInvoke 会阻止它,所以不要从服务于用户界面的线程中调用它。

还是先来段自己喜欢的控制台代码:

1using System;

2

3namespace ConsoleApplication1

4{

5 class Class1

6 {

7 public delegate void AsyncEventHandler();

8

9 void Event1()

10 {

11 Console.WriteLine("Event1 Start");

12 System.Threading.Thread.Sleep(2000);

13 Console.WriteLine("Event1 End");

14 }

15

16 void Event2()

17 {

18 Console.WriteLine("Event2 Start");

19 int i=1;

20 while(i<1000)

21 {

22 i=i+1;

23 Console.WriteLine("Event2 "+i.ToString());

24 }

25 Console.WriteLine("Event2 End");

26 }

27

28 void CallbackMethod(IAsyncResult ar)

29 {

30 ((AsyncEventHandler) ar.AsyncState).EndInvoke(ar);

31 }

32

33

34 [STA Thread]

35 static void Main(string[] args)

36 {

37 long start=0;

38 long end=0;

39 Class1 c = new Class1();

40 Console.WriteLine("ready");

41 start=DateTime.Now.Ticks;

42

43 AsyncEventHandler asy = new AsyncEventHandler(c.Event1);

44 IAsyncResult ia=asy.BeginInvoke(null,null);

45 c.Event2();

46 asy.EndInvoke(ia);

47

48 end =DateTime.Now.Ticks;

49 Console.WriteLine("时间刻度差="+ Convert.ToString(end-start) );

50 Console.ReadLine();

51 }

52 }

53}

54

此程序简单,异步的处理过程在代码43-46这几行

结果如下:

现在让我们来看看同步处理

修改代码43-46这几行代码:

c.Event1();

c.Event2();

结果如下:

前者的时间刻度大大小于后者

我们可以明显地看到异步运行的速度优越性

2.方案2-轮询异步调用完成

由BeginInvoke 返回的IAsyncResult.IsCompleted属性获取异步操作是否已完成的指示,发现异步调用何时完成.

从用户界面的服务线程中进行异步调用时可以执行此操作。轮询完成允许调用线程在异步调用在ThreadPool 线程上执行时继续执行。

再次修改代码43-46这几行代码:

AsyncEventHandler asy = new AsyncEventHandler(c.Event1);

IAsyncResult ia=asy.BeginInvoke(null,null);

c.Event2();

while(!ia.IsCompleted)

{

}

asy.EndInvoke(ia);

3.方案3-使用WaitHandle等待异步调用

IAsyncResult.AsyncWaitHandle属性获取用于等待异步操作完成的WaitHandle WaitHandle.WaitOne方法阻塞当前线程,直到当前的WaitHandle收到信号

使用WaitHandle,则在异步调用完成之后,但在通过调用EndInvoke结果之前,可以执行其他处理

再次修改代码43-46这几行代码:

AsyncEventHandler asy = new AsyncEventHandler(c.Event1);

IAsyncResult ia=asy.BeginInvoke(null,null);

c.Event2();

ia.AsyncWaitHandle.WaitOne();

4.方案4-异步调用完成时执行回调方法

如果启动异步调用的线程不需要是处理结果的线程,则可以在调用完成时执行回调方法。回调方法在ThreadPool 线程上执行。

若要使用回调方法,必须将引用回调方法的AsyncCallback 委托传递给BeginInvoke。也可以传递包含回调方法将要使用的信息的对象。例如,可以传递启动调用时曾使用的委托,以便回调方法能够调用EndInvoke。

再次修改代码43-46这几行代码:

AsyncEventHandler asy = new AsyncEventHandler(c.Event1);

asy.BeginInvoke(new AsyncCallback(c.CallbackMethod),asy);

c.Event2();

总结:

四种使用BeginInvoke和EndInvoke进行异步调用的常用方法。在调用BeginInvoke 之后,可以执行下列操作:

1.进行某些操作,然后调用EndInvoke 一直阻止到调用完成。

2.使用System.IAsyncResult.AsyncWaitHandle 属性获取WaitHandle,使用它的WaitOne 方法一直阻止执行直到发出WaitHandle 信号,然后调用EndInvoke。

3.轮询由BeginInvoke 返回的IAsyncResult,确定异步调用何时完成,然后调用EndInvoke。

4.将用于回调方法的委托传递给BeginInvoke。异步调用完成后,将在ThreadPool 线程上执行该方法。该回调方法将调用EndInvoke。

注意:

每次都要调用EndInvoke来完成异步调用。

相关主题
相关文档
最新文档