繁体   English   中英

什么时候会从 UI 线程返回异步等待方法? 在第一次等待还是在内部等待?

[英]When will an async await method return from the UI-Thread? At the first await or at the inner await?

我在 UI 线程上的 WPF 中使用异步等待。 我有一个关于 async await 在特定情况下如何工作的问题。 我将尝试用一个例子来解释它。

背景

假设我有带有单击事件处理程序ButtonA_Click()的按钮 A 和带有ButtonB_Click()的按钮 B。 点击处理程序将检查RunLoop()方法是否仍在运行。 如果它没有运行,它们会启动RunLoop()

问题:

  1. 当调用(外部) await RunLoop()时,事件处理程序是否会从 UI 线程返回?
  2. 或者它会在RunLoop()的(内部)等待处返回,因为它可以在Runloop()的开头执行同步代码( _isStopped = false; )。

如果 1. 为真,它可能会导致赛车状况,或者? 当同时调用两个点击处理程序时,它们将在 UI-Thread 上紧接着运行。 因此,第二个事件处理程序可能会在第一次执行 RunLoop() 之前运行。 在这种情况下, _isStopped 对于第二个事件处理程序仍然是错误的,它也会启动一个RunLoop() 因此 2 RunLoop()将处于活动状态。 那是对的吗?

(PS:我知道,如果 1. 是这种情况,我可以通过将_isStopped = false放入点击处理程序来解决这个问题,但这个问题更多地是关于了解当方法以这种方式嵌套时异步等待是如何工作的)。

代码

private bool _isStopped = true;
private List<Customer> _customers;  // will be filled from somewhere else

public async void ButtonA_Click()
{
    // do some stuff synchronously

    if (_isStopped)
        await RunLoop();
}

public async void ButtonB_Click()
{
    // do some stuff synchronously

    if (_isStopped)
        await RunLoop();
}

private async Task RunLoop()
{
    _isStopped = false;

    while (_customers.Any())
    {
        _customers.Remove(...);
        await Task.Run(() => ProcessStuff());
    }        

    _isStopped = true;
}

得到答案后更新:

这些链接帮助我更好地理解它

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/task-asynchronous-programming-model

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/control-flow-in-async-programs

await被赋予一个不完整Task时,控制权返回给调用方法。

这意味着首先,必须给await一个Task ,这意味着您调用的方法必须在await执行任何操作之前返回。 其次, Task必须是不完整的。 如果await看到一个完整的Task ,则同步恢复执行。

在您的情况下,假设ButtonA_Click()运行:

  1. ButtonA_Click()开始同步运行。
  2. RunLoop()被执行,它开始同步运行。
  3. Task.Run被执行,这将返回一个不完整的Task
  4. RunLoop()中的await看到不完整的Task并返回它自己的不完整Task
  5. ButtonA_Click()中的await会看到不完整的Task并且通常会返回Task ,但该方法是void ,因此它什么也不返回。
  6. 控制权被传递给任何称为ButtonA_Click()的东西。

Microsoft 有一些关于使用 async 和 await 进行异步编程的好文章,值得一读。

这将是第二个选择。 async方法中的代码同步运行,直到遇到等待未完成Taskawait语句。

请注意,如果所有等待的Tasks在等待之前完成,或者没有任何代码实际上需要await语句,它可能会一直同步运行。

暂无
暂无

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

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