怎么使用异步,就是用委托进行处理,如果委托对象在调用列表中只有一个方法,它就可以异步执行这个方法。委托类有两个方法,叫做BeginInvoke和EndInvoke,它们是用来异步执行使用。
异步有三种模式
等待模式,在发起了异步方法以及做了一些其它处理之后,原始线程就中断,并且等待异步方法完成之后再继续。
轮询模式,原始线程定期检查发起的线程是否完成,如果没有则可以继续做一些其它的事情。
回调模式,原始线程一直在执行,无需等待或检查发起的线程是否完成。在发起的线程中的引用方法完成之后,发起的线程就会调用回调方法,由回调方法在调用EndInvoke之前处理异步方法的结构。
在学习异步编程之前,先看看BeginInvoke和EndInvoke方法。
BeginInvoke方法
在调用BeginInvoke时,参数列表中的实参组成如下:
1) 引用方法需要的参数。
2) 两个额外的参数——callback参数和state参数。
BeginInvoke从线程池中获取一个线程并且在新的线程开始时运行引用方法。
BeginInvoke返回给调用线程一个实现IasyncResult接口的对象。这个接口引用包含了异步方法的当前状态,原始线程然后可以继续执行。
EndInvoke方法
它接受一个由BeginInvoke方法返回的IasyncResult对象的引用,并找到它关联的线程。
如果线程池的线程已经退出,EndInvoke做如下的事情。
1) 它清理退出线程的状态并且释放它的资源。
2) 它找到引用方法返回的值并且把它的值作为返回值。
如果当EndInvoke被调用时线程池的线程仍然在运行,调用线程就会停止并等待,直到清理完毕并返回值。因为EndInvoke是为开启的线程进行清理,所以必须确保对每一个BeginInvoke都调用EndInvoke。
如果异步方法触发了异常,在调用EndInvoke时会抛出异常。
等待模式
在这种模式里,原始线程发起一个异步方法的调用,做一些其它处理,然后停止并等待,直到开启的线程结束。如下图
这段代码产生了如下输出。
既然我们已经看到了BeginInvoke和EndInoke的最简单形式,可以进一步了解IasyncResult了,它是使用这些方法的必要部分。
BeginInvoke返回一个IasyncResult接口的引用(内部是AsyncResult类的对象)。AsyncResult类表现了异步方法的状态。如下图:
当我们调用委托对象的BeginInvoke方法时,系统创建了一个AsyncResult类的对象。然而,它不返回类的对象的引用,而是返回对象中包含的IasyncResult接口的引用。
AsyncResult对象包含一个叫做AsyncDelegate的属性,它返回一个指向被调用来开启异步方法的委托的引用。但是这个属性是类对象的一部分而是接口的一部分。
IsCompleted属性返回一个布尔值,表示异步方法是否完成。
AsyncState属性返回一个对象的引用,它被作为BeginInvoke方法调用时的state参数。它返回object类型的引用,稍后再讲解。。
轮询模式
在轮询模式中,原始线程发起了异步方法的调用,做一些其它处理,然后使用IAsyncResult对象的IsCompleted属性来定期检查开启的线程是否完成。如果异步方法已经完成,原始线程就调用EndInvoke并继续。否则,它做一些其它处理,然后过一会儿再检查。如下图:
这段代码产生了如下输出。
回调模式
在之前的等待模式与轮询模式中,初始线程继续它自己的控制流程,直到它知道开启的线程完成。然后,它获取结果并继续。
回调模式的不同之处在于,一旦初始线程发起了异步方法,它就自己管自己了,不再考虑同步。当异步方法调用结束之后,系统调用一个用户自定义的方法来处理结束,并且调用委托的EndInvoke方法。这个用户自定义的方法叫做回调方法或回调。
BeginInvoke的参数列表中最后的两个额外参数被回调方法用做:
1) 第一个参数,callback参数,是回调方法的名字。