我遇到了一个非常奇怪的行为。经过大量挖掘后,我能够找到一个场景,该场景表明(显然)直接从 WFP 应用程序使用任务等待无法按预期工作。但是,创建任务并在其中执行等待工作正常。
我使用以下步骤来说明(使用 VS 2013)。在新的 WPF 应用程序中使用此 main.xaml.cs:
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
static async Task<bool> Test_int()
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Thread t = new Thread(() =>
{
Thread.Sleep(1000);
tcs.SetResult(true);
//Console.WriteLine("TCS set");
});
t.Start();
//int i = tcs.Task.Result; //<-- this always works, but doesn't take advantage of await semantics
var ret = await tcs.Task;
return ret;
}
static void Test()
{
var tt = Test_int();
//(1)
tt.Wait();
//Console.WriteLine("Test done");
}
public MainWindow()
{
InitializeComponent();
//option 1 -- works
Task t = new Task(Test);
t.Start();
t.Wait();
//option 2 -- hangs indefinitely
Test();
}
}
}
我看到的行为是运行方法 Test() 直接导致应用程序挂起(在标记为 (1) 的等待行中),而在任务中运行它会正确运行并完成。
我通过在任务上下文中运行解决了我最初的问题,但我想了解问题的原因。顺便说一句,在控制台应用程序中运行时,相同的 Test() 方法确实可以直接工作。
为什么直接从 WPF 应用程序运行时不等待工作(以相同的方式)?
最佳答案
您遇到了 classic deadlock scenario我在我的博客上描述的。总之,await
默认情况下会捕获一个“上下文”并使用它来恢复 async
方法。在这种情况下,它是一个 UI 上下文,如果您阻塞 UI 线程(通过调用 Wait
),则 async
方法无法恢复并且永远不会完成。
正确的解决方案是使用 await
而不是 Wait
。
此外,您不应使用Task
构造函数、Start
或Thread
(使用Task.Run
相反,但前提是您需要在后台线程上执行代码)。
我建议您阅读我的 async
intro blog post然后是我的 async
best practices MSDN article .他们应该可以帮助您。
关于c# - 任务异步/等待不适用于 WPF,因为它在其他场景中有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27573834/