任务异步/等待在 WPF 中不起作用,因为它在其他方案中有效
本文关键字:因为 其他 方案 有效 不起作用 等待 异步 WPF 任务 | 更新日期: 2023-09-27 18:34:55
我遇到了一个非常奇怪的行为。经过大量挖掘,我能够找到一个场景,该场景表明(显然(直接从 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 应用程序运行时等待不起作用(以相同的方式(?
您遇到了我在博客上描述的经典死锁场景。总之,默认情况下,await
将捕获"上下文"并使用它来恢复async
方法。在本例中,它是一个 UI 上下文,如果阻止 UI 线程(通过调用 Wait
(,则 async
方法无法恢复且永远不会完成。
正确的解决方案是使用 await
而不是 Wait
.
此外,不应使用 Task
构造函数、Start
或 Thread
(请改用 Task.Run
,但仅当需要在后台线程上执行代码时(。
我建议您阅读我的async
介绍博客文章,然后阅读我的async
最佳实践 MSDN 文章。他们应该帮助你。