如何ConfigureAwait(false)防止Ui死锁 [英] How ConfigureAwait(false) Prevent Ui Deadlocks

查看:62
本文介绍了如何ConfigureAwait(false)防止Ui死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这个问题已经被无休止地询问了,但是仍然如此.我想我缺少任何东西.当我们要以异步方式更新UI(出于参数目的,是WinForm UI)时.但是我们不能使用async/await关键字,而必须使用ConfigureAwait(false).据我了解,告诉"它可以在任何可用线程上自行恢复而不需要等待主线程的任务.它可以通过释放UI来避免死锁,因为UI无需等待较长的过程就可以完成,而任务不需要等待主UI线程可用.

I Know that this question has been asked endlessly, but still. I think i am missing somthing. When we want updating UI( WinForm UI for the sake of argument ) in asynchronously manner. But we cannot using the async /await keyword and we have to use the ConfigureAwait(false). As i understand it "Tells" the task that it can resume itself on any available thread instead of waiting to to the main thread. Its preventing the deadlock by free the UI for not waiting for the long process to be completed and task is not waiting for the main UI thread to be available.

以下代码演示了经典的死锁

The following code demonstrate the classical deadlock

public void Button_Click()
{

    SomeTextBox.Text =LongProcessAsync().Result;
}

所以现在我的问题开始了:).在长时间处理任务完成之后,UI线程最终如何更新UI.

So now my question start :). How eventually UI thread update UI after long proccess task has completed.

是因为任务将结果传递到另一个UI进程来完成作业吗?UI队列消息如何与那部分相关?当说仅一个线程更新ui时,是否意味着该线程在应用程序的整个生命周期中都存在,还是仅一个线程正在更新ui,但是可以创建一个新线程来执行此操作?

Is it because task passing the result to another UI process to complete the job ? How UI queue message related to that parts ? When saying only one thread updating the ui , does it mean that this thread live for the all life cycle of the application or only one thread is updating ui but a new thread can be created and do the stuff ?

谢谢

推荐答案

我建议您阅读斯蒂芬·克雷里(Stephen Cleary)关于此主题的博客文章:

I recommend reading Stephen Cleary's blog post on this topic: Don't Block on Async Code which explains how the deadlock happen and how to avoid it.

请注意死锁"与死锁"之间的区别.和阻止的用户界面".死锁发生在两个线程互相等待时,阻塞的UI发生在UI线程忙/阻塞且无法处理UI消息时.这里使用 ConfigureAwait(false)不会阻止阻止的UI",但是会阻止死锁".

Pay attention to the difference of "deadlock" and "blocked UI". Deadlock happens when two threads are waiting for each other, Blocked UI happens when UI thread is busy/blocked and cannot process UI messages. Here using ConfigureAwait(false) doesn't prevent "blocked UI", but prevents "deadlock".

编写运行任务的异步库方法时,为防止可能的死锁,建议通过 ConfigureAwait(false)运行任务.即使在您的库用户通过调用 Result Wait 来获取异步方法的结果的情况下,也可以防止死锁.

When you write an async library methods which runs a task, to prevent a possible deadlock it's recommended to run your task by ConfigureAwait(false). It's to prevent deadlock even in case the users of your library get the result of your async method by calling Result or Wait.

ConfigureAwait(false)基本上告诉:不要在此行之后返回原始上下文并继续在线程池线程上执行.

ConfigureAwait(false) basically tells: not to come back to the original context after this line and continue execution on thread pool thread.

要更好地理解它,请看以下示例:

To understand it better, look at this example:

// UI code 
1:  private void button1_Click(object sender, EventArgs e) 
2:  { 
3:      var result = GetDataAsync().Result; 
4:      MessageBox.Show(result); 
5:  } 

// A library code
6:  public async Task<string> GetDataAsync() 
7:  { 
8:      await Task.Delay(1000); 
9:      return "Data"; 
10: } 

考虑以下事实:

  • 在Windows窗体中,所有UI代码都在单个线程中执行;UI线程.

  • In Windows Forms, all UI code executes in a single thread; the UI thread.

Result 方法阻塞调用线程,直到任务结果准备就绪.

Result method of the Task blocks the calling thread until the result of the task is ready.

这是这里发生的事情:

  • 在第3行,将在直到第8行的UI线程中调用并执行 GetDataAsync .
  • 在第8行,将创建一个任务,该任务将在线程池线程上运行,并在运行该任务后等待告诉,该执行应在先前捕获的上下文(这是UI线程上下文)中继续进行.
  • 未完成的任务返回到原始调用方(在第3行),该调用方将在将来完成(在完成类似8的任务然后运行第9行之后)完成.
  • 然后将执行第3行的 Result 方法,该方法将阻止任务,直到任务完成并且 GetDataAsync 的最终结果准备就绪.
  • 第8行的等待任务完成时,调度程序尝试在UI线程中运行第9行,但UI线程被阻塞!因此无法执行第9行,并且无法完成 GetDataAsync .
  • At line 3, GetDataAsync will be called and executed in UI thread up to line 8.
  • At line 8 a task will be created and will run on thread pool thread and await is telling after running that task, the execution should continue in the previously captured context (Which is UI thread context).
  • An uncompleted task returns to the original caller (at line 3) which will be completed in future (after completing task of like 8 and then running line 9).
  • Then the Result method at line 3 will be executed, which blocks the task until it gets completed and final result of GetDataAsync is ready.
  • When the awaited task of line 8 completes, the scheduler tries to run line 9 in the UI thread, but the UI thread is blocked! So line 9 cannot be executed and GetDataAsync cannot be completed.

发生死锁:UI线程正在等待 GetDataAsync 完成,而 GetDataAsync 正在等待主线程自由执行其余代码.

A deadlock happens: UI thread is waiting for GetDataAsync to complete, and GetDataAsync is waiting for main thread to be free to execute rest of the code.

为避免死锁,您应该使用 await ,而不是通过 Wait Result 来获取异步方法的结果.但是正如我前面提到的,在上述情况下,如果您作为库开发人员通过 ConfigureAwait(false)运行您的任务(此处为 Task.Delay ),则可以防止死锁,因为它告诉不要在此行之后返回原始上下文,而是继续在线程池线程上执行.因此,在第8行,它告诉我们继续在线程池线程中运行,因此虽然UI线程被阻止,但是第9行执行并将数据返回到UI线程并取消阻止.

To avoid the deadlock, instead of getting the result of async method by Wait or Result, you should use await. But as I mentioned earlier, in above scenario, if you as a library developer run your task (here Task.Delay) by ConfigureAwait(false) it prevents deadlock, because it tells not to come back to the original context after this line and continue execution on thread pool thread. So at line 8, it tells to continue in thread pool thread, so while the UI thread is blocked, but line 9 executes and returns data to UI thread and unblock it.

// UI code 
1:  private void button1_Click(object sender, EventArgs e) 
2:  { 
3:      var result = GetDataAsync().Result; 
4:      MessageBox.Show(result); 
5:  } 

// A library code
6:  public async Task<string> GetDataAsync() 
7:  { 
8:      await Task.Delay(1000).ConfigureAwait(false); 
9:      return "Data"; 
10: } 

但是,再次提醒您,作为UI开发人员,您应始终使用 await 来等待 Task ,而不应使用 Result 等待.

But again, keep in mind, as the UI developer, you should always use await for awaiting the Task and you should not use Result or Wait.

这篇关于如何ConfigureAwait(false)防止Ui死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆