欢迎来到.net学习网

欢迎联系站长一起更新本网站!QQ:879621940

您当前所在位置:首页 »  .NET本质论第一卷:公共语言运行库教程 » 正文

本教程章节列表

net本质论-异步方法调用(二)

创建时间:2013年01月18日 09:59  阅读次数:(5023)
分享到:
当异步方法执行完后,需要一种机制来收集调用的结果.以用于进一步处理。这个机制就是EndInvoke方法。EndInvoke方法是委托类型的第四个方法。像BeginInvoke方法一样,EndInvoke方法的签名与委托类型的Invoke方法的签名是相关的。考虑下面在本讨论中所使用的c#委托类型:
public double Add (double x,  double y, out double z.  rof bool overflow);

对应的EndInvoke将是这样的
Public double EndInvoke(out double z,ref bool oerflow,System.IasyncResult call);

上述两个方法的签名在三个方面是关联的:其一,EndInvoke将返回与Invoke相同的类型化的值。这是可能的,因为EndInvoke直到底层方法执行完毕并且返回值可用时才返回;其二,EndInvoke省略了任何出现在Invoke方法中按值传递的(pass-by-value)参数,这是因为按值传递的参数仅仅对于发行调用是需要的.并且它们并不表示方法调用的结果,最后,EndInvoke接收一个IAsyncResult类型的附加参数。这个参数允许调用方指出所感兴趣的收集结果来自于哪个调用。这个参数是必需的,因为你可以在同一个委托对象上分发多个异步调用。IAsyncResult参数指出你对哪个调用感兴趣。

图6.12展示了当目标方法执行时,BeginInvoke和EndInvoke是如何让调用方的线程继续执行的。这个图有几个有趣的地方:其一,CLR使用同步的Invoke方法调用目标方法,不过是从一个CLR托管工作线程中调用,而不是从调用方的线程中调用;其二,在调用已经执行完毕后,工作线程发出调用完成的信号,并返回到工作队列。通过对额外的异步调用重用工作线程,可在进程的生存期内分摊线程创建所带来的开销。
异步方法调用
异步方法调用
图6.12 异步方法调用

线程池的线程数量将会随时间增加或减少。当一个工作请求到达一个队列时,CLR就试图将该调用分发到一个现存的工作线程中。如果当前的每个工作线程都忙于服务上一个请求,CLR将开启一个新的线程来服务于这个新请求。

为了避免系统饱和.CLR设置了其创建工作线程数量的上限。默认的上限是每个CPU 25个线程,但承载CLR的进程可以使用及。ICorThreadpool::CorSetMaxThreads方法改变这个默认值。你可以通过调用System.Thereading.ThreadPool.GetMaxThreads方法从基于CLR的程序查询这个上限值。

如果系统中出现突发事件,那么,线程的数量达到上限就是可能的。然而,如果该状况只是瞬变的峰值,则不能代表应用程序的稳定状态。因而,当更少数量的线程就能完成同样的工作时,保持每个线程都存活将是很浪费的。因此,假如上作线程没有被使用,一段时间后便会减少。在编写本书时,工作线程消失的周期是30秒。

前面异步方法调用的示例展示了:调用方的线程将在调用对象产生一个集合点(rendezvus),以处理异步调用的结果。如果调用的结果并不重要,那么,忽略对EndInvoke的调用也是合法的。这种调用方式有时被称为发出并遗忘(fire-and-forget),或者单向(one-way)调用。通常在方法没有返回值和按引用传递的参数时使用这种调用风格。当你可以安全地忽略方法失
败时也可以使用这种风格,因为任何由目标方法抛出的异常,在单向调用的方式下都会被CLR取消引。

你可以不通过调用对象的显式集合点处理异步方法调用的结果。为了达到这个目的,在发出调用时传递一个异步的完成例程( comoletion routine)给BeginInvoke方法。

完成例程必须匹配System.AsyncCallback委托的原型(System.AsyncCallback委托的原型参见示例6.11)。你可以把完成例程作为倒数第二个自变量传递给BeginInvoke。在目标方法执行之后,完成例程将由工作线程立即调用。完成例程将被作为单独的参数,传递给调用对象。通常情况下。对于用于处理这个调用完成的任何状态,都将被作为最后一个参数传递给BeginInvoke;完成例程将通过IAsyncResult.AsyncState属性取回这个状态。

示例6.12展示了一个使用完成例程的异步方法调用。注意,在这个示例中,Completed方法负责调用EndInvoke方法,收集来自于方法调用的任何结果。为了在完成时调用EndInvoke方法,传递那个委托对象的引用将作为最后一个参数传递给BeginInvoke方法。如果需要更复杂的处理,那么,可以传递一个更复杂的对象。

示例6.12 带回调的异步调用
public delegate double
Add(double x, double y,out double z,ref bool overflow);

Public static void CallIt(Add add){
Bool overflow=true;
//创建回调委托
AsyncCallback cb=new AsyncCalllBack(completed);
//发现该调用并且返回
IasyncResult ar=add.BeginInvoke(3,4,out z,ref overflow,cb,add);
}

//这个方法在调用完成时将被工作方线程调用
Public static void Completed(IasyncResult call){
Double z; bool overflow=true;
Add add=(Add)call.AsyncState;
Double result=add.EndInvoke(out z,ref overflow,call);
Console.Write(“{0},{1},{2}”,result,overflow,z);
}
来源:.net学习网
说明:所有来源为 .net学习网的文章均为原创,如有转载,请在转载处标注本页地址,谢谢!
【编辑:Wyf】

打赏

取消

感谢您的支持,我会做的更好!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

最新评论

共有评论0条
  • 暂无任何评论,请留下您对本文章的看法,共同参入讨论!
发表评论:
留言人:
内  容:
请输入问题 61+38=? 的结果(结果是:99)
结  果: