【问题标题】:Multi layer async control flow多层异步控制流
【发布时间】:2017-06-10 23:00:13
【问题描述】:

我想知道这个例子中的线程是如何流动的。有异步事件处理程序,它调用另一个异步方法,该方法有两个等待。我可以这样理解流程吗:

  • 1)UI线程调用button1_Click,依次调用LoadStringAsync方法
  • 2)LoadStringAsync 首先调用GetFirstNameAsync
  • 3)GetFirstNameAsync 返回一个未完成的任务,LoadStringAsync 等待这个任务
  • 4) LoadStringAsync 依次返回未完成的任务 button1_Click 等待 LoadStringAsync 返回的 Task
  • 5) UI 线程离开 button1_Click。这就是为什么 UI 线程不是 被屏蔽了。
  • 6) 当 GetFirstNameAsync 最终完成时,LoadStringAsync 可以 continue,这意味着 UI 线程将再次进入,并执行 下一行是另一个等待。
  • 8) GetLastNameAsync 返回一个未完成的任务 LoadStringAsync 等待 GetLastNameAsync 返回的任务
  • 9) button1_Click 等待 LoadStringAsync 返回的任务
  • 10) UI 线程再次离开 button1_Click,并执行其他操作。
  • 11) 重复相同的步骤。

我的假设正确吗?或者这里有死锁的情况。

private async void button1_Click(object sender, RoutedEventArgs e) 
{ 
string s = await LoadStringAsync(); 
textBox1.Text = s; 
}

static async Task<string> LoadStringAsync() 
{ 
string firstName = await GetFirstNameAsync(); 
string lastName = await GetLastNameAsync(); 
return firstName + ” ” + lastName; 
}

【问题讨论】:

  • 您描述的流程似乎是正确的。无法确定这里是否存在死锁情况,因为您没有提供有关 LoadStringAsync、GetFirstNameAsync 等内容的详细信息。如果那里没有任何阻塞调用,应该没问题。

标签: c# .net asynchronous async-await deadlock


【解决方案1】:

您的流程几乎是正确的。只有一个修改:一个方法不可能返回两次(步骤 4 和 9)。由于LoadStringAsync已经返回了一个未完成的任务,它只是直接返回到第二个await处的UI线程。

您提供的代码中没有死锁。

【讨论】:

  • 另外可能值得指出的是,如果他在LoadStringAsync() 内部的等待中使用.ConfigureAwait(false),则在整个await LoadStringAsync() 完成之前不需要再次打扰UI 线程;将使用 ThreadPool 线程来代替。
  • @Stephen Cleary,感谢您的评论。在过去的几天里,我一直在阅读您的博客。在阅读了您的死锁博客之后,我也认为没有死锁问题。但是您的死锁博客没有两个等待示例,然后我阅读了此博客 blogs.msdn.microsoft.com/pfxteam/2011/01/13/… 。我的示例代码实际上是从那里获取的,Stephen Toub 说这是一个僵局(除非我完全理解他的话是错误的)......
  • @sellotape 我可以这样理解:如果使用 .ConfigureAwait(false),线程池中的线程 A 将处理 LoadStringAsync() 中的两个等待,线程 A 会将最终字符串返回给 s 变量button_Click 方法。那么哪个线程将更新 textBox1 ?如果不是 UI 线程,我猜它会抛出异常。 ——
  • @zhengyu - 不如“意志”强;这更像是告诉编译器您不需要原始上下文来继续(在等待完成之后)。任务可能会在 ThreadPool 线程上运行,但使用 ConfigureAwait(true)(或省略,因为它是默认值),任务之后的 continuation 将在相同的上下文中继续,并且在你的 UI,这也意味着在 UI 线程上。所以我说它“......不会需要......”并不意味着它不会,但至少你给了它不这样做的选项。
  • @zhengyu:死锁是由于Toub使用Result的例子。正如他在同一篇文章中解释的那样,使用await 而不是Result 可以避免死锁。您的示例代码已经做了。有一个await 还是两个都没关系。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-12
  • 2012-11-02
  • 1970-01-01
  • 2021-09-19
  • 2022-01-03
  • 1970-01-01
相关资源
最近更新 更多