本文实例形式展示了C#中异步挪用的实现要领,并对其道理进行了较为深入的分析,现以教程的方法分享给大家供大家参考之用。具体如下:
首先我们来看一个简单的例子:
小明在烧水,等水烧开以后,将开水灌入热水瓶,然后开始整理家务
小文在烧水,在烧水的过程中整理家务,等水烧开以后,放下手中的家务活,将开水灌入热水瓶,然后继续整理家务
这也是日常生活中很常见的情形,小文的供职效率明显要高于小明。从C#措施执行的角度考虑,小明使用的同步措置惩罚惩罚方法,而小文则使用的异步措置惩罚惩罚方法。
同步措置惩罚惩罚方法下,事务是按挨次一件一件措置惩罚惩罚的;而异步方法则是,将子操纵从主操纵中疏散出来,主操纵继续进行,子操纵在完成措置惩罚惩罚的时候通知主操纵。
在C#中,异步通过委托来完成。请看下面的例子:
class Program { static TimeSpan Boil() { Console.WriteLine("水壶:开始烧水..."); Thread.Sleep(6000); Console.WriteLine("水壶:水已经烧开了!"); return TimeSpan.MinValue; } delegate TimeSpan BoilingDelegate(); static void Main(string[] args) { Console.WriteLine("小文:将水壶放在炉子上"); BoilingDelegate d = new BoilingDelegate(Boil); IAsyncResult result = d.BeginInvoke(BoilingFinishedCallback, null); Console.WriteLine("小文:开始整理家务..."); for (int i = 0; i < 20; i++) { Console.WriteLine("小文:整理第{0}项家务...", i + 1); Thread.Sleep(1000); } } static void BoilingFinishedCallback(IAsyncResult result) { AsyncResult asyncResult = (AsyncResult)result; BoilingDelegate del = (BoilingDelegate)asyncResult.AsyncDelegate; del.EndInvoke(result); Console.WriteLine("小文:将热水灌到热水瓶"); Console.WriteLine("小文:继续整理家务"); } }
上面的例子是一个最简单的异步挪用的例子,没有对异步挪用函数做任何参数通报以及返回值校验。这个例子反应了小文烧水的流程,首先小文将水壶放在炉子上,在界说好委托以后,就使用BeginInvoke要领开始异步挪用,即让水壶开始烧水,于是小文便开始整理家务。水烧开后,C#的异步模型会触发由BeginInvoke要领所指定的回调函数,也就是水烧开后的措置惩罚惩罚逻辑由这个回调函数界说,此时小文将水灌入热水瓶并继续整理家务。
由此可见,在C#中实现异步挪用其实并不庞大,首先创建一个异步措置惩罚惩罚函数,并针对其界说一个委托;然后在挪用函数的时候,使用委托的BeginInvoke要领,指定在函数措置惩罚惩罚完成时的回调函数(如果不需要对完成事件做措置惩罚惩罚,可以给null值),并指定所需的参数(如果没有参数,也可以给null值);最后在回调函数中措置惩罚惩罚完成事件。
请注意上例回调函数中的EndInvoke挪用,EndInvoke会使得挪用线程梗阻,直到异步函数措置惩罚惩罚完成。显然,紧接在BeginInvoke后面的EndInvoke使用方法与同步挪用等价。
EndInvoke挪用的返回值也就是异步措置惩罚惩罚函数的返回值。我们把措施稍作改削,将Boil要领改成下面的形式:
static TimeSpan Boil() { DateTime begin = DateTime.Now; Console.WriteLine("水壶:开始烧水..."); Thread.Sleep(6000); Console.WriteLine("水壶:水已经烧开了!"); return DateTime.Now - begin; }
然后将BoilingFinishedCallback改成下面的形式:
static void BoilingFinishedCallback(IAsyncResult result) { AsyncResult asyncResult = (AsyncResult)result; BoilingDelegate del = (BoilingDelegate)asyncResult.AsyncDelegate; Console.WriteLine("(烧水一共用去{0}时间)", del.EndInvoke(result)); Console.WriteLine("小文:将热水灌到热水瓶"); Console.WriteLine("小文:继续整理家务"); }
那么我们就可以在EndInvoke的时候,获得由Boil异步措置惩罚惩罚函数返回的时间值。事实上,如果界说的BoilingDelegate委托存在参数列表,那么我们也可以在BeginInvoke的时候,将所需的参数传给异步措置惩罚惩罚函数。BeginInvoke/EndInvoke函数的签名与界说它们的委托签名有关。
注意:在改削后的BoilingFinishedCallback要领中,为了得到委托实例以便获取异步措置惩罚惩罚函数的返回值,我们给与了下面的转换:
AsyncResult asyncResult = (AsyncResult)result; BoilingDelegate del = (BoilingDelegate)asyncResult.AsyncDelegate;
这样才华获得挪用异步措置惩罚惩罚函数的委托的实体。
.NET措置惩罚惩罚异步函数挪用,事实上是通过线程来完成的。这个过程有以下几个特点:
1.异步函数由线程完成,这个线程是.NET线程池中的线程
2.凡是情况下,.NET线程池拥有500个线程(固然这个数量可以设置),每当挪用BeginInvoke开始异步措置惩罚惩罚时,异步措置惩罚惩罚函数就由线程池中的某个线程卖力执行,而用户无法控制具体是由哪个线程卖力执行
3.由于线程池中线程数量有限,因此当池中线程被完全占用时,新的挪用请求将使函数不得不期待空余线程的呈现。此时,措施的效率会有所影响。
为了验证这些特点,请看下面的措施: