我遇到了一个非常奇怪的行为。经过大量挖掘后,我能够找到一个场景,表明(显然)使用任务直接从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)的await行中),而在任务中运行它并正确运行并完成。
我通过在任务的上下文中运行来解决我原来的问题,但我想了解问题的原因。 BTW相同的Test()方法在控制台应用程序中运行时可以直接工作。
直接从WPF应用程序运行时,为什么不等待工作(以相同的方式)?
答案 0 :(得分:6)
您正在遇到我在博客上描述的classic deadlock scenario。总之,await
默认情况下会捕获&#34;上下文&#34;并使用它来恢复async
方法。在这种情况下,它是一个UI上下文,如果您阻止UI线程(通过调用Wait
),则async
方法无法恢复并且永远不会完成。
正确的解决方案是使用await
代替Wait
。
此外,您不应该使用Task
构造函数,Start
或Thread
(而是使用Task.Run
,但前提是需要< / em>在后台线程上执行代码。)
我建议您阅读我的async
intro blog post,然后阅读async
best practices MSDN article。他们应该帮助你。