任务异步/等待无法在WPF中工作,因为它在其他方案中有效

OSH*_*OSH 1 c# wpf async-await

我遇到了一个非常奇怪的行为.经过大量挖掘后,我能够找到一个场景,表明(显然)直接从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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我看到的行为是运行方法Test()直接导致应用程序挂起(在标有(1)的await行中),而在任务中运行它正确运行并完成.

我通过在任务的上下文中运行来解决我的原始问题,但我想了解问题的原因.BTW相同的Test()方法在控制台应用程序中运行时可以直接工作.

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

Ste*_*ary 6

遇到了我在博客上描述的经典死锁场景.总之,await默认情况下将捕获"上下文"并使用它来恢复该async方法.在这种情况下,它是一个UI上下文,如果您阻止UI线程(通过调用Wait),则该async方法无法恢复并且永远不会完成.

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

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

我建议你阅读我的async介绍博客文章,然后阅读我的async最佳实践MSDN文章.他们应该帮助你.

  • @CoryNelson:答案包含所有必要信息;链接包含更多详细信息。 (2认同)