本次来介绍一下如何使用委托的 BeginInvoke 方法来实现异步编程
先来看看异步调用的方法
老板派发给我count个任务。我使用printNum来完成这些个任务。
static void printNum(int count){
Debug.Log("员工:做事去咯!" + Thread.CurrentThread.ManagedThreadId);
for(int i=0;i<count;i++){
Debug.Log("员工:我做完第{0}件事",i);
Thread.Sleep(1);//休息一下
}
Debug.Log("员工:做完咯!" + Thread.CurrentThread.ManagedThreadId);
}
然后我定义了一个委托来完成任务
static Action<int> action = printNum;
等待模式
老板让我去做个任务,啥事都不干一直站在我面前等我完成。(我能怎么办我也很绝望!)
Debug.Log("老板:你去做点事!");
var iar = action.BeginInvoke(5,null,null);
Debug.Log("老板:我就站你面前等你做完!还想偷懒!");
Debug.Log("等待完工并验收!");
action.EndInvoke(iar);
Debug.Log("老板:这傻逼终于做完了!");
运行结果
轮询模式
老板让我去做个任务,然后一直来问你做完了没。(烦不烦呀,越催越慢!)
Debug.Log("老板:你去做点事!");
iar = action.BeginInvoke(5,null,null);
while(!iar.IsCompleted){
Debug.Log("老板:做完了不?");
Debug.Log("员工:等等还差一点!");
Thread.Sleep(1);
}
Debug.Log("验收!");
action.EndInvoke(iar);
Debug.Log("老板:让我问这么多次才做完,真慢!");
运行结果
回调模式
老板让我去做个任务,让我做完了通知他!(老板多让人省心)
Debug.Log("老板:你去做点事,做完通知我!");
iar = action.BeginInvoke(5,finish,action);
static void finish(IAsyncResult iar){
Debug.Log("老板:做完了?");
Debug.Log("员工:做完了!");
Debug.Log("老板:我看看!");
Action<int> ac = iar.AsyncState as Action<int>;
ac.EndInvoke(iar);
Debug.Log("老板:还行,先这样吧!");
}
运行结果
现在我们来分析一下BeginInvoke的参数
倒数第一个参数是自定义的参数,会保存在BeginInvoke的返回值IAsyncResult的AsyncState中。
倒数第二个参数为完成异步任务后的回调函数
其他参数为委托的基本参数
调用BeginInvoke时,clr会从线程池中获取一个线程来运行方法
调用EndInvoke 会阻塞等待委托完成。当然如果已经完成了就不会阻塞。
改方法还会做一些资源回收。如果在异步执行时出现异常,调用EndInvoke会抛出异常。
如果委托有放回值,EndInvoke 也会带放回值
记得BeginInvoke后必须调用EndInvoke。即使你已经知道异步调用完成。
IAsyncResult 接口
AsyncState 是调用BeginInvoke的最后一个参数
IsCompleted 表示异步操作是否完成
CompletedSynchronously 表示是否同步完成的(这不是与刚才说的有冲突么? 同步完成应该会在一些自定义的继承IAsyncResult中会出现,你可能会设计成某个条件达成时,不采用启用新线程来触发委托,直接执行委托,等待返回也就是在调用BenginInvoke后,任务已经完成了,完全没有异步的效果。这时候CompletedSynchronously 为true)
AsyncWaitHandle 等待处理,这里只介绍 WaitOne(); 调用 WatiOne 会阻塞等待 异步完成!还可以设置超时时间,如果超时还为完成会停止阻塞等待!