【问题标题】:What happens to the callee's thread when an async function is invoked synchronously当异步函数被同步调用时,被调用者的线程会发生什么
【发布时间】:2013-07-04 08:39:59
【问题描述】:

在下面的示例中,当同步调用异步“Process”函数时,我可以看到对“await Task.Delay(1000)”的调用导致 UI 挂起。

我知道我可以通过调用“await Task.Delay(1000).ConfigureAwait(false)”或将“Process”调用包装在另一个任务中来避免挂起。我可以理解问题在于同步上下文,并且我知道 await 正在做一些花哨的事情,即如果我将调用“await Task.Delay(1000)”替换为“Task.Delay(1000).Wait()”UI不挂。

有人可以解释一下这种行为吗(我确实尝试查看 ildasm 代码,但没有帮助)。非常感谢。

public MainWindow()
{
    InitializeComponent();
    Loaded += OnLoaded;
}

public async void OnLoaded(object sender, RoutedEventArgs args)
{
    var task = Process();
    MessageBox.Show(task.Result);
}

public async Task<String> Process()
{
    await Task.Delay(1000);
    return "";
}

【问题讨论】:

  • 简而言之:task.Result 的意思是“挂起 UI 直到任务完成,然后使用结果”。 await task 的意思是“将控制权交给我的调用者;当任务完成时,安排任务的延续在未来方便的时间运行,然后使用结果”。

标签: c# .net asynchronous async-await


【解决方案1】:

首先,方法总是同步调用。当OnLoaded被调用时,它会调用Process方法。

Process 方法调用Task.Delay 方法并返回对它等待的Task&lt;string&gt; 对象的引用。这意味着await之后的代码稍后执行,Process方法此时返回。

OnLoaded 方法返回对 Task&lt;string&gt; 对象的引用,该对象存储在 task 变量中。然后在任务上调用Result getter。这会阻塞当前线程,直到任务完成。

一秒钟后,Process 方法尝试继续。因为您在 UI 线程上启动了任务,所以调度程序会尝试在 UI 线程上调度 Process 方法。但 UI 线程被 Result getter 调用阻塞,因此永远不会执行 return ""; 语句。

【讨论】:

  • 对不起,事实并非如此,UI 挂起并且 return "" 甚至没有被调用(请设置断点并自己查看)。
  • 谢谢,不知道为什么它没有点击我。 :)
  • +1。我更详细地描述了这个死锁on my blogMSDN article,我的博客文章包含更多信息的链接,包括几个死锁演示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-25
  • 1970-01-01
  • 2013-07-12
  • 2014-06-10
相关资源
最近更新 更多