在下面的示例中,当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 "";
}
答案 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 "";
语句。