-
C#线程 入门-异步委托
异步委托
ThreadPool.QueueUserWorkItem没有提供一种简单的机制来在线程执行完毕后从线程取回返回值。异步委托调用(简称异步委托)解决了这一问题,允许在两个方向上传递任意数量的类型化参数。此外,异步委托上未处理的异常可以方便地在原始线程(或更准确地说是调用EndInvoke的线程)上重新抛出,因此不需要显式处理。
不要将异步委托与异步方法(以Begin或End开头的方法,例如File.BeginRead / File.EndRead)混淆。异步方法在外部遵循类似的协议,但是它们存在是为了解决更难的问题,我们将在C#4.0的第23章“简而言之”中进行描述。
通过异步委托启动工作任务的方法如下:
- 实例化一个以您要并行运行的方法为目标的委托(通常是预定义的Func委托之一)。
- 在委托上调用BeginInvoke,保存其IAsyncResult返回值。 BeginInvoke立即返回给调用者。然后,您可以在池线程正在工作时执行其他活动。
- 当需要结果时,在委托上调用EndInvoke,传入保存的IAsyncResult对象。
在下面的示例中,我们使用异步委托调用与主线程并发执行,主线程是一种返回字符串长度的简单方法:
1
2
3
4
5
6
7
8
9
10
|
static void Main() { Func< string , int > method = Work; IAsyncResult cookie = method.BeginInvoke ( "test" , null , null ); // // ... here's where we can do other work in parallel... // int result = method.EndInvoke (cookie); Console.WriteLine ( "String length is: " + result); } |
static int Work (string s) { return s.Length; }
EndInvoke做三件事。首先,它会等待异步委托完成执行(如果尚未执行)。其次,它接收返回值(以及任何ref或out参数)。第三,它将所有未处理的工作程序异常抛出回调用线程。
如果您使用异步委托调用的方法没有返回值,则仍然(在技术上)有义务调用EndInvoke。实际上,这是有争议的。没有EndInvoke警察对违规者进行处罚!但是,如果您选择不调用EndInvoke,则需要考虑worker方法上的异常处理,以避免无提示的失败。
您还可以在调用BeginInvoke时指定一个回调委托-一种接受IAsyncResult对象的方法,该方法在完成后会自动调用。这允许煽动线程“忘记”异步委托,但是在回调端需要一些额外的工作:
static void Main() { Func<string, int> method = Work; method.BeginInvoke ("test", Done, method); // ... // } static int Work (string s) { return s.Length; } static void Done (IAsyncResult cookie) { var target = (Func<string, int>) cookie.AsyncState; int result = target.EndInvoke (cookie); Console.WriteLine ("String length is: " + result); }
BeginInvoke的最后一个参数是填充IAsyncResult的AsyncState属性的用户状态对象。它可以包含您喜欢的任何内容;在这种情况下,我们使用它将方法委托传递给完成回调,因此我们可以在其上调用EndInvoke。