b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

methodinvoker?c#回调函数简单例子?wpf methodinvoker?创建无阻塞的异步调用(一)(2)

电脑杂谈  发布时间:2016-11-17 20:03:42  来源:网络整理

● 一旦线程池内产生了空闲线程,它会立即被分配给异步任务等待队列,之后线程池中仍然不具备空闲线程,应用程序主线程进入挂起状态继续等待空闲线程,这样 的调用一直持续到异步调用被执行完30次。

针对以上结果,我们对于异步调用可以总结为以下内容:

● 每次异步调用都在新的线程中执行,这个线程来自于.NET线程池。

● 线程池有自己的执行上限,如果你想要执行多次耗费时间较长的异步调用,那么线程池有可能进入一种”线程饥饿”状态,去等待可用线程的产生。

BeginInvoke和EndInvoke

我们已经知道,如何在不阻塞调用线程的情况下执行一个异步调用,但我们无法得知异步调用的执行结果,及它何时执行完毕。为了解决以上问题,我们可以使用EndInvoke。EndInvoke在异步方法执行完成前,都会造成线程的阻塞。因此,在调用BeginInvoke之后调用EndInvoke,效果几乎完全等同于以阻塞模式执行你的函数(EndInvoke会使调用线程挂起,一直到异步函数执行完毕)。但是,.NET是如何将BeginInvoke和EndInvoke进行绑定呢?答案就是IAsyncResult。每次我们使用BeginInvoke,返回值都是IAsyncResult类型,它是.NET追踪异步调用的关键值。每次异步调用之后的结果如何?如果要了解具体执行结果,IAsyncResult便可视为一个标签。通过这个标签,你可以了解异步调用何时执行完毕,更重要的是,它可以保存异步调用的参数传值,解决异步函数上下文问题。

我们现在通过几个例子来了解IAsyncResult。如果之前对它了解不多,那么就需要耐心的将它领悟,因为这种类型的调用是.NET异步调用的关键内容。

输出结果:

methodinvoker?c#回调函数简单例子?wpf methodinvoker?创建无阻塞的异步调用(一)

回到文章初始提到的”窗体动态更新”问题,如果你将上述代码运行在一个WinForm程序中,会发现窗体依然陷入”假死”。对于这种情况,你可能会陷入疑惑:之前说异步函数都执行程池中,因此可以肯定异步函数的执行不会引起UI线程的忙碌,但为什么窗体依然陷入了”假死”?问题就在于EndInvoke。EndInvoke此时扮演的角色就是”线程锁”,它充当了一个调用线程与异步线程之间的调度器,有时调用线程需要使用异步函数的执行结果,那么调度线程就需要在异步执行完之前一直等待,直到得到结果方可继续运行。EndInvoke一方面负责异步函数的执行状况,一方面将调用线程挂起。

因此在Win Form环境下,UI线程的”假死”并不是因为线程忙碌造成,而是被EndInvoke”善意的”暂时封锁,它只是为了等待异步函数的完成。

我们可以对EndInvoke总结如下:

● 在执行EndInvoke时,调用线程会进入挂起状态,一直到异步函数执行完成。

● 使用EndInvoke可以使应用程序得知异步函数何时执行完毕。

● 如果将上述写法称为”异步”,你一定觉得这种”异步”徒具其名,虽然知道异步函数何时执行完毕,也得到了异步函数的传值,但我们的调用线程仍然会等待函数执行完毕,在等待过程中线程阻塞,实际上与同步调用无异。

如何捕捉异常?

现在我们把问题稍微复杂化,考虑异步函数抛出异常的一种情形。我们需要了解在何处捕捉到异常,是BeginInvoke,还是EndInvoke?甚至是有没有可能无法捕捉异常?答案是EndInvoke。BeginInvoke的工作只是开始线程池对于异步函数的执行工作,EndInvoke则需要处理函数执行完成的所有信息,包括其中产生的异常,。

执行以上代码后,你将发现只有在使用EndInvoke时,才会捕捉到异常,否则异常将丢失。需要注意的是,直接在编译器中运行程序是无法产生捕获异常的,只有在Debug、Release环境下运行,异常才会以对话框的形式直接弹出。

向函数中传递参数

现在我们来改变一下异步函数,让它接收一些参数。

下面我们使用BeginInvoke与EndInvoke来调用这个函数,首先,我们创建一个匹配该函数的委托签名。


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-21102-2.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...