【问题标题】:Task async/await not working from WPF as it works in other scenarios任务 async/await 不能从 WPF 工作,因为它在其他情况下工作
【发布时间】:2014-12-20 05:10:36
【问题描述】:

我遇到了一个非常奇怪的行为。经过大量挖掘后,我找到了一个场景,该场景显示(显然)直接从 WFP 应用程序使用任务 await 不能按预期工作。但是,创建一个任务并在其中执行 await 可以正常工作。

我使用以下步骤进行说明(使用 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 行中),而在任务中运行它会正确运行并完成。

我通过在任务上下文中运行解决了我最初的问题,但我想了解问题的原因。顺便说一句,在控制台应用程序中运行时,相同的 Test() 方法确实可以直接工作。

直接从 WPF 应用程序运行时,为什么不等待工作(以相同的方式)?

【问题讨论】:

  • 您应该避免在 WPF 中调用 Task.Wait()。正如您所做的那样,很容易引入死锁。
  • @Cory Nelson 这是问题的一个例证。等待只是表明(1)等待永远不会返回。
  • 请记住,死锁有两个或多个端点。 Wait() 只是一端。另一个是await

标签: c# wpf async-await


【解决方案1】:

您遇到了我在博客中描述的classic deadlock scenario。总之,await 默认情况下将捕获一个“上下文”并使用它来恢复async 方法。在这种情况下,它是一个 UI 上下文,如果您阻塞 UI 线程(通过调用 Wait),那么 async 方法将无法恢复并且永远不会完成。

正确的解决方案是使用await 而不是Wait

此外,您不应使用 Task 构造函数、StartThread(改为使用 Task.Run,但仅当您需要在后台线程上执行代码时)。

我建议您阅读我的async intro blog post,然后阅读我的async best practices MSDN article。他们应该会帮助你。

【讨论】:

  • 不确定是因为它有有用的链接而投赞成票,还是因为好的答案包含信息而不是链接而投反对票。
  • @CoryNelson:答案包含所有必要的信息;链接包含更多详细信息。
  • 您的博文正是我所缺少的。优秀的阅读。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-12
  • 2018-07-15
  • 2020-03-15
  • 1970-01-01
  • 2019-08-25
  • 2021-05-15
  • 1970-01-01
相关资源
最近更新 更多