发文章
发文工具
撰写
网文摘手
文档
视频
思维导图
随笔
相册
原创同步助手
其他工具
图片转文字
文件清理
AI助手
留言交流
C#异步调用获取结果方法:主要有三种,也可以说是四种(官方说四种,电子书说三种),官方在MSDN上已经有详细的说明: 链接
需要了解到获取异步执行的返回值,意味着你需要调用Delegate的BeginInvoke方法,而不是Invoke方法。
第一种就是书上没有说的,但是官方还是给出来的,就是通过调用EndInvoke方法来获取内容,查看如下代码:
class MyState { public int ThreadId = 0; public int Data = 0; public MyState() { } } class AsyncInvoke { private MyState State = null; public AsyncInvoke() { State = new MyState(); } private int TakesAWhile(int data, int ms) { Console.WriteLine("TakesAWhile started"); Thread.Sleep(ms); Console.WriteLine("TakesAWhile completed"); return ++data; } public delegate int TakesAWhileDelegate(int data, int ms); public void RunEndInvoke() { TakesAWhileDelegate dl = new TakesAWhileDelegate(TakesAWhile); IAsyncResult ar = dl.BeginInvoke(5, 3000, null, null); int result = 0; result = dl.EndInvoke(ar); Console.WriteLine(string.Format("Result: {0}", result)); } }
TakesAWhile startedTakesAWhile completedResult: 6
通过上面可以知道使用EndInvoke阻塞了主线程(RunEndInvoke函数),同时需要使用BeginInvoke的返回值ar作为EndInvoke的入参。
第二种方法Polling(轮询)BeginInvoke的返回值(IAsyncResult中的属性IsCompleted),将RunEndInvoke替换成下面的函数RunPolling:
public void RunPolling() { TakesAWhileDelegate dl = new TakesAWhileDelegate(TakesAWhile); IAsyncResult ar = dl.BeginInvoke(5, 3000, null, null); while (ar.IsCompleted == false) { Thread.Sleep(500); } int result = 0; result = dl.EndInvoke(ar); Console.WriteLine(string.Format("Result: {0}", result)); }
public void RunInvoke() { TakesAWhileDelegate dl = new TakesAWhileDelegate(TakesAWhile); int result = dl.Invoke(5, 3000); Console.WriteLine(string.Format("Result: {0}", result)); }
public void RunEndInvoke() { TakesAWhileDelegate dl = new TakesAWhileDelegate(TakesAWhile); IAsyncResult ar = dl.BeginInvoke(5, 3000, null, null); // Do others in main thread. Console.WriteLine("Do others in main thread..."); // int result = 0; result = dl.EndInvoke(ar); Console.WriteLine(string.Format("Result: {0}", result)); }
Do others in main thread...TakesAWhile startedTakesAWhile completedResult: 6
这样你可以放别的工作在BeginInvoke的之后,在主线程执行,等到执行了,可以使用阻塞主线程来等待异步执行的结果来进行下一步的需要,这样情况能够部分提高工作效率,通常用于执行相互独立的模块,然后再等待两边结果(主线程以及异步线程的结果)来进行下一步的操作。
好了,讲第三种的方法来获取异步结果了,就是Wait Handle。 handle是通过BeginInvoke的返回值(ar)中的一个属性AsyncWaitHandle来获得的。一开始AsyncWaitHandle是没有初始化的,但是只要引用该属性,操作系统实现它,同时调用其waitone函数去等待异步执行完的信号。如果使用没有带参的waitone函数,则无限期阻塞主线程来等待异步执行,一旦执行完,则返回, 如下代码所示:
public void RunWaitHandle() { TakesAWhileDelegate dl = new TakesAWhileDelegate(TakesAWhile); IAsyncResult ar = dl.BeginInvoke(5, 3000, null, null); ar.AsyncWaitHandle.WaitOne(); Console.WriteLine("Wait for 3 seconds."); int result = 0; result = dl.EndInvoke(ar); ar.AsyncWaitHandle.Close(); Console.WriteLine(string.Format("Result: {0}", result)); }
如果使用带参的,如waitone(1000, false)来判断当前返回值是true则意味着等待1秒,第二参数来判断是否退出同步。
从上面三种方法来看,的确是挺好的,但是每次都需要主线程去等待,大哥不好当,所以就有了第四种方法,就是使用BegingInvoke的第三个参数,该函数是在BeginInvoke调用的函数执行完后自动执行,不然也不叫做callback。第四个参数通常将异步函数的delegate传递过去,这样在callback函数中就可以方便的获取到异步函数的执行结果或者返回值。
public void AsyncCompleted(IAsyncResult ar) { if (ar != null) { Console.WriteLine("After the async operation."); TakesAWhileDelegate dl = ar.AsyncState as TakesAWhileDelegate; int result = 0; result = dl.EndInvoke(ar); Console.WriteLine(string.Format("Result: {0}", result)); } } public void RunAsyncCallback() { TakesAWhileDelegate dl = new TakesAWhileDelegate(TakesAWhile); IAsyncResult ar = dl.BeginInvoke(5, 3000, AsyncCompleted, dl); Console.WriteLine("Finish RunAsyncCallback."); }
public void RunAsyncCallback2() { TakesAWhileDelegate dl = new TakesAWhileDelegate(TakesAWhile); dl.BeginInvoke(5, 3000, ar => { Console.Write("After async operation."); int result = 0; result = dl.EndInvoke(ar); Console.WriteLine(string.Format("Result: {0}", result)); }, null); Console.WriteLine("Finish RunAsyncCallback."); }
private MyState TakesAWhile(int data) { Console.WriteLine("TakesAWhile started"); Thread.Sleep(3000); Console.WriteLine("TakesAWhile completed"); return new MyState(){Data=++data, ThreadId=Thread.CurrentThread.ManagedThreadId}; } private delegate MyState TaskAWhileDelegate2(int data); public void RunEndInvokeWithStructReturn() { TaskAWhileDelegate2 dl = new TaskAWhileDelegate2(TakesAWhile); IAsyncResult ar = dl.BeginInvoke(5, null, null); MyState state = null; state = dl.EndInvoke(ar); Console.WriteLine(string.Format("Data: {0}, ThreadId: {1}", state.Data, state.ThreadId)); }
private void TakesAWhile(int data, int ms, ref MyState state) { Console.WriteLine("TakesAWhile started"); Thread.Sleep(ms); Console.WriteLine("TakesAWhile completed"); state.Data = ++data; state.ThreadId = Thread.CurrentThread.ManagedThreadId; } private delegate void TakesAWhileDelegate3(int data, int ms, ref MyState state); public void RunEndInvokeWithRefStruct() { TakesAWhileDelegate3 dl = new TakesAWhileDelegate3(TakesAWhile); IAsyncResult ar = dl.BeginInvoke(5, 3000, ref State, null, null); dl.EndInvoke(ref State, ar); // this State could be any other reference to MyState Console.WriteLine(string.Format("Data: {0}, ThreadId: {1}", State.Data, State.ThreadId)); }
上面讲述的主要是Thread或者task的异步调用BeginInvoke的结果获取方法,但是如果该异步函数中涉及到输出参数,就如刚才说的复杂对象中的成员是controller的话,就又有一章来讲了,对于UI以及后台线程的交互这是一个重要点,如果你不想你的UI经常假死的话,请收看下一回:Controller中BeginInvoke与Invoke的区别以及应用。
AD的优势是异步函数的强类型保证,参数的输入都是规定好的(delegate声明),如果需要传递参数可以在函数中使用ref关键字(只针对引用类型,值类型无效果)。由于异步调用时使用task底层实现的,所以他具有了task的优势,方便使用,但是也有其缺点,不能够想thread那样提供丰富的对线程设置(后台,优先级,不能中断)。
来自: 昵称10504424 > 《工作》
0条评论
发表
请遵守用户 评论公约
.NET异步编程总结
WriteLine("主线程"); IAsyncResult result = printDelegate.BeginInvoke("Hello World.", null, null); Console.W...
MSDN-异步编程概述 [C#] - bitman的专栏 - 博客园
EndInvoke 的参数包括您需要异步执行的方法的 out 和 ref 参数(在 Visual Basic 中为 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。TestMethod 有一个 out 参数(在 Visual ...
C#线程系列讲座(1):BeginInvoke和EndInvoke方法
1. BeginInvoke和EndInvoke方法。三、直接使用EndInvoke方法来获得返回值 当使用BeginInvoke异步调用方法时,如果方法未执行完,End...
异步编程
folderName = Console.这就是BeginInvoke()方法的返回值ret,一个IAsyncResult类型的对象。BeginInvoke()方法的第2个参数指定当异步调用结束时回调ShowFolderSize()函数,第3个参数AsyncState被填入了...
多线程(一):异步委托
-->//在次线程中调用Add()IAsyncResult iftAr = b.BeginInvoke(10, 10, null, null);Code-->static void AddComplete(IAsyncResult itfAR){WriteLine("AddComplete() 执行在线程on thread {...
C#同步方法和异步方法的区别
C#同步方法和异步方法的区别 同步方法和异步方法的区别。这里主要是主程序等待异步方法,等待异步方法的结果。rs.一般都是已Begin开头End结尾构成一对,异步委托方法,外加两个回调函数和AsyncState参...
关于异步编程(AsyncCallback委托,IAsyncResult接口,BeginInvoke方法,EndInvoke方法的使用小总结)
关于异步编程(AsyncCallback委托,IAsyncResult接口,BeginInvoke方法,EndInvoke方法的使用小总结)让我们来看看同步异步的区别:同步方法调用在程序继续执行之前需要等待同步方法执行完毕返回结果异步方...
C#异步编程概述
本文论述了.NET下异步编程的一般原则并给出示例,解决了Windows GUI应用中操作网络和文件时界面假死的问题。
C#线程通信和异步委托
C#线程通信和异步委托。关于异步委托,这里要用到里面的两个方法BeginInvoke 和 EndInvoke.该方法与您需要异步执行的方法具有相同的参数,还有另外两个可选参数。public <方法返回值类型>EndInvo...
微信扫码,在手机上查看选中内容