2

在下面的示例中,当同步调用异步“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 "";
}
4

1 回答 1

3

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

Process方法调用该Task.Delay方法并取回Task<string>对它等待的对象的引用。这意味着后面的代码await稍后执行,并且该Process方法在此时返回。

OnLoaded方法取回Task<string>对它存储在 task变量中的对象的引用。然后在任务上调用Resultgetter。这会阻塞当前线程,直到任务完成。

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

于 2013-07-06T12:12:42.783 回答