简体   繁体   English

异步方法完成时如何等待部分代码回调/执行

[英]How does awaiting part of code calledback/executed when asynchronous method finished

I've read about asynchronous programming in C#, but I still do not fully understand how continuation of async method is executed.我在 C# 中阅读了有关异步编程的内容,但我仍然不完全了解如何执行异步方法的延续。 From my understanding, Asynchronous programming is not about multithreading.据我了解,异步编程与多线程无关。 We can run async method on UI Thread, and it later continues on that UI Thread (while not blocking and continuing to respond to other messages from message loop).我们可以在 UI 线程上运行异步方法,然后它会在该 UI 线程上继续运行(同时不会阻塞并继续响应来自消息循环的其他消息)。

This is basic message loop most GUI apps have:这是大多数 GUI 应用程序具有的基本消息循环:

while (1)
{
    bRet = GetMessage(&msg, NULL, 0, 0);

    if (bRet > 0)  // (bRet > 0 indicates a message that must be processed.)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    ...

DispatchMessage() calls UI event handlers. DispatchMessage()调用 UI 事件处理程序。 And the code inside the event handlers should not block the main thread.并且事件处理程序中的代码不应阻塞主线程。 For that reason if we want to, ie create a button that loads a heavy data from disk, we can use async method like this: (simplified pseudo code)出于这个原因,如果我们想要,即创建一个从磁盘加载大量数据的按钮,我们可以使用这样的异步方法:(简化伪代码)

public async Task ButtonClicked()
{
  loadingBar.Show();
  await AsyncLoadData();
  loadingBar.Hide();
}

When execution reaches await AsyncLoadData();当执行到达await AsyncLoadData(); line, it stores the context and returns the Task object.行,它存储上下文并返回任务 object。 DispatchMessage() finishes and message loop repeatedly comes to the bRet = GetMessage(&msg, NULL, 0, 0); DispatchMessage()完成并且消息循环反复到达bRet = GetMessage(&msg, NULL, 0, 0); line.线。

So my question is, how the rest code is executed?所以我的问题是,rest 代码是如何执行的? Is finished async operation triggers a new message, that is then handled by DispatchMessage() again?完成的异步操作是否触发了一条新消息,然后由DispatchMessage()再次处理? Or the message loop has another method (after dispatch), that checks for finished async operations?或者消息循环有另一种方法(在调度之后),它检查完成的异步操作?

So my question is, how the rest code is executed?所以我的问题是,rest 代码是如何执行的? Is finished async operation triggers a new message, that is then handled by DispatchMessage() again?完成的异步操作是否触发了一条新消息,然后由 DispatchMessage() 再次处理? Or the message loop has another method (after dispatch), that checks for finished async operations?或者消息循环有另一种方法(在调度之后),它检查完成的异步操作?

await by default will capture a "context" and use that to resume the execution of the method. await默认情况下将捕获“上下文”并使用它来恢复方法的执行。 This "context" is SynchronizationContext.Current , falling back on TaskScheduler.Current .这个“上下文”是SynchronizationContext.Current ,依赖于TaskScheduler.Current UI apps provide a SynchronizationContext , eg, WindowsFormsSynchronizationContext or DispatcherSynchronizationContext . UI 应用程序提供SynchronizationContext ,例如WindowsFormsSynchronizationContextDispatcherSynchronizationContext When the await completes, it schedules the continuation of the method onto that context (in this case, onto the SynchronizationContext ).await完成时,它会将方法的延续安排到该上下文(在本例中为SynchronizationContext )。

For WinForms, the syncctx uses Control.BeginInvoke , which will post a Win32 message which is handled by the WinProc .对于 WinForms, syncctx 使用Control.BeginInvoke ,它将发布由 WinProc 处理的 Win32 消息

For WPF, the syncctx posts to its Dispatcher , which adds the callback to the dispatch queue .对于 WPF, syncctx 发布到它的Dispatcher ,这会将回调添加到 dispatch queue中。 This queue is also processed by a Win32 WinProc loop .此队列也由 Win32 WinProc 循环处理

Alex Davies wrote an excellent book on this, it is called "Async in C# 5", I strongly recommend reading it. Alex Davies 在这方面写了一本很棒的书,叫做“Async in C# 5”,我强烈推荐阅读它。 I can't tell low level details behind this, but at the high level CLR will create something like this:我无法说出这背后的低级细节,但在高级 CLR 将创建如下内容:

void __buttoncliked_remaining_code_1(...) { 
    loadingBar.Hide(); 
} 

So, a specific event will be triggered indicating that async job has completed.因此,将触发一个特定事件,指示异步作业已完成。 Then __buttoncliked_remaining_code_1() will be executed, sinchronously, just like any regular C# function.然后__buttoncliked_remaining_code_1()将同步执行,就像任何常规的 C# function 一样。 CLR will use for that any thread, but most likely it will reuse the one that encountered await keyword, which in your case might be GUI thread. CLR 将用于任何线程,但很可能它会重用遇到 await 关键字的线程,在您的情况下可能是 GUI 线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM