简体   繁体   English

任务异步/等待无法在WPF中工作,因为它在其他情况下也可以工作

[英]Task async/await not working from WPF as it works in other scenarios

I ran into a very odd behavior. 我遇到了一个非常奇怪的行为。 After a lot of digging I was able to find a scenario that shows that (apparently) using task await directly from a WFP application doesn't work as expected. 经过大量的挖掘,我发现了一个场景,该场景表明(显然)直接从WFP应用程序中使用任务等待无法正常工作。 However, creating a task and doing the await within it works ok. 但是,创建一个任务并在其中等待是可以的。

I used the following steps to illustrate (using VS 2013). 我使用以下步骤进行了说明(使用VS 2013)。 In a new WPF application use this main.xaml.cs: 在新的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();
        }
    }
}

The behavior I see is that running the method Test() directly causes the application to hang (in the await line marked with (1)), while running it inside a task runs correctly and finish. 我看到的行为是,运行方法Test()直接导致应用程序挂起(在标记为(1)的等待行中),而在任务内部运行它可以正常运行并完成。

I solved my original problem by running in the context of a task, but I would like to understand the cause of the problem. 我通过在任务上下文中运行解决了最初的问题,但是我想了解问题的原因。 BTW the same Test() method does work directly when running in a console application. 顺便说一句,当在控制台应用程序中运行时,相同的Test()方法确实可以直接工作。

Why doesn't await work (the same way) when running directly from a WPF application? 直接从WPF应用程序运行时,为什么不等待工作(相同方式)?

You're running into a classic deadlock scenario that I describe on my blog. 您正在遇到我在博客中描述的经典死锁场景 In summary, await by default will capture a "context" and use that to resume the async method. 总之,默认情况下, await将捕获“上下文”,并使用该上下文来恢复async方法。 In this case, it's a UI context, and if you block the UI thread (by calling Wait ), then the async method cannot resume and never completes. 在这种情况下,它是一个UI上下文,并且如果您阻塞UI线程(通过调用Wait ),那么async方法将无法恢复并且永远不会完成。

The proper solution is to use await instead of Wait . 正确的解决方案是使用await而不是Wait

Furthermore, you shouldn't use the Task constructor, Start , or Thread (use Task.Run instead, but only if you need to execute code on a background thread). 此外,您不应使用Task构造函数, StartThread (而应使用Task.Run ,而仅当您需要在后台线程上执行代码时)。

I recommend you read my async intro blog post and then my async best practices MSDN article . 我建议您阅读我的async介绍博客文章 ,然后阅读我的async最佳实践MSDN文章 They should help you out. 他们应该帮助您。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM