当同步调用异步函数时,被调用者的线程会发生什么

时间:2013-07-06 11:30:39

标签: c# .net asynchronous async-await

在下面的示例中,当async" Process"函数是同步调用的,我可以看到调用"等待Task.Delay(1000)"导致UI挂起。

我知道我可以通过调用" await Task.Delay(1000)来避免挂起.ConfigureAwait(false)"或包装"过程"在另一个任务中调用。我可以理解问题在于synchornizationcontext,我知道等待用它做一些奇特的事情,即如果我替换了呼叫"等待Task.Delay(1000)" to" Task.Delay(1000).Wait()"用户界面不会挂起。

有人可以解释一下这种行为(我确实试过看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 "";
}

1 个答案:

答案 0 :(得分:3)

首先,始终同步调用方法。调用OnLoaded时,它会调用Process方法。

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

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

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