我有一个带有以下代码的控制台应用程序
static void Main(string[] args) {
Method();
Console.ReadKey();
}
private static void Method() {
Task t = DoSomething();
t.Wait();
Console.WriteLine("Finished");
}
private static async Task DoSomething() {
await Task.Run(() =>
Thread.Sleep(1000));
}
一切都按照我的预期运行,控制台在运行程序后一秒钟显示“已完成”。当我将相同的代码移动到Windows应用程序中时,我发现该程序只是停止
private void button1_Click(object sender, EventArgs e) {
Task t = DoSomething();
t.Wait();
MessageBox.Show("Finished");
}
private static async Task DoSomething() {
await Task.Run(() =>
Thread.Sleep(1000));
}
调试器显示当前执行的行是t.Wait(),即使在运行了DoSomething方法中的Task之后也是如此。
我是否需要在Windows应用程序中执行某些不同的操作,而我不需要在控制台应用程序中执行此操作?还是我从根本上误解了什么?
答案 0 :(得分:5)
这是经常发生的事情。你造成了僵局。
简单地说,像WinForms和WPF这样的框架“强制”了一个线程同步上下文,这意味着每当你启动一个新任务时,你的其余代码将继续在它启动的同一个线程上。这样做是为了确保,例如,在UI线程上启动的代码将在任务返回后继续在同一线程上运行。
因为您在任务上阻止(使用Wait
方法),并且任务正在尝试将值返回到该阻塞线程,所以两个线程都进入死锁状态
在控制台应用程序中不会发生此行为,因为没有强制执行线程同步上下文,任务的继续可以在完全不同的第三个线程上运行。
Stephen Cleary在这里解释得非常好:http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html