线程 vs BeginInvoke vs 异步

9

我对线程和异步编程还不熟悉。我正在尝试学习这些概念,到目前为止我已经理解了,但是有一个问题要问。

比如说我想调用一个叫做 GetAllUsers() 的方法,它需要很长时间才能执行,我想以一种不会阻塞资源并保持 UI 响应的方式来执行它。所以,我理解可以用以下三种方式来实现(请告诉我这些是否正确或者我完全弄错了):

1) 线程:我可以生成一个新线程,并将 GetAllUsers 方法作为 threadstart。这将在不同的线程上启动方法的执行,使我的 UI 保持响应,并且当调用完成时,我可以使用路由技术来更新 UI 控件,即 InvokeRequired。我的理解正确吗?

或者

2) 异步委托:我可以创建一个委托。创建一个新实例并将其指向 GetAllUsers 方法。然后使用 BeginInvoke 方法。BeginInvoke 在幕后将生成一个新线程并运行我的方法,使 UI 保持响应。当调用完成时,回调方法将被调用,再次使用路由技术来更新 GUI 线程上的控件。我的理解正确吗?

或者

3) 异步/等待:将外部方法标记为async,并将对GetAllUsers方法的调用标记为await。这也可以保持UI响应性,因为运行它的线程可以跳出并执行其他工作,直到调用此缓慢方法完成。我的理解正确吗?

现在问题是 - 如果您阅读下面链接中的第2段,它说异步/等待不会导致创建额外的线程。那么,异步/等待如何在不创建任何其他线程的情况下提供与上述前两个解决方案相同的输出。解决方案1和2将导致多线程,但异步解决方案不会。异步/等待在底层如何工作?

http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx#BKMK_Threads

1个回答

13

我的理解正确吗?

是的,你的理解是正确的。

那么问题是-如果您阅读下面链接中的第二段落,则会说async/await不会导致创建额外的线程。那么async/await如何在不创建任何额外线程的情况下实现与上述前两个解决方案相同的输出呢?

async修饰符和await操作符并不一定会创建新线程。实现异步操作的机制由您调用await的类型处理。如果您使用await Task.Run(() => YourMethod()),则Task.Run会使用一个线程池线程来执行操作。

然而,如果您可以重构您的方法,使GetAllUsers使用异步I/O调用而不是线程,那么await将不需要使用线程来进行异步操作。例如,如果GetAllUsers大部分时间都在等待从服务器下载,使用异步Web API将允许您使该方法异步化而无需使用额外的线程。

在这种情况下,即使您必须使用Task.Runawait,这里仍有很好的优势-您可以重新设计您的方法以使用await,而不破坏其逻辑控制流,保持异常处理的清晰,并且无需担心使用BeginInvoke来推回UI线程 - 使用await,所有这些“麻烦”都为您处理,您的代码可以保持非常接近原始代码,非常简洁。


3
为什么会有人在这里给负面评价呢? - Reed Copsey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接