【问题标题】:How to await until Task.ContinueWith inner task finishes如何等待 Task.ContinueWith 内部任务完成
【发布时间】:2015-04-19 15:39:30
【问题描述】:

看看这段代码:

    private async Task InnerTask(bool outerTaskResult)
    {
        Console.WriteLine("2");
        await Task.Factory.StartNew(() => Thread.Sleep(10000));
        Console.WriteLine("3");
    }

    private async void Button2_Click(object sender, RoutedEventArgs e)
    {
        var task = Task.FromResult(false);
        Task<Task> aggregatedTask = task.ContinueWith(task1 => InnerTask(task1.Result));
        Console.WriteLine("1");
        await aggregatedTask;
        Console.WriteLine("4");
    }

想要的输出是:

1
2
3
4

但我明白了:

1
2
4
3

这可能与 InnerTask 在不同的线程上执行有关。

我使用 ContinueWith 是因为原始代码中的任务是以这种方式动态创建和排队的。

使用 .Wait() 方法(见下文)有效,但我认为这是一个坏主意,因为该方法是阻塞的。

task.ContinueWith(task1 => InnerTask(task1.Result).Wait())

这里的正确方法是什么?

【问题讨论】:

    标签: c# .net task-parallel-library async-await task


    【解决方案1】:

    您可以使用TaskExtensions.Unwrap()(这是Task&lt;Task&gt; 上的扩展方法)解开外部任务并检索内部任务:

    private async void Button2_Click(object sender, RoutedEventArgs e)
    {
        var task = Task.FromResult(false);
        Task aggregatedTask = task.ContinueWith(task1 => InnerTask(task1.Result)).Unwrap();
        Console.WriteLine("1");
        await aggregatedTask;
        Console.WriteLine("4");
    }
    

    请注意,为了简化整个事情,您可以 await 处理您的任务,而不是 ContinueWith 样式延续:

    private async void Button2_Click(object sender, RoutedEventArgs e)
    {
        var task = Task.FromResult(false);
    
        Console.WriteLine("1");
    
        var result = await task;
        await InnerTask(result);
    
        Console.WriteLine("4");
    }
    

    【讨论】:

    • Unwrap 实际上并不需要。问题中await aggregatedTask的返回值其实就是内部任务。
    • 他有一个Task&lt;Task&gt;,这是他正在等待的外部任务,这就是为什么它在之前完成外部Console.WriteLine。他可以简单地await
    • @PanagiotisKanavos 确实,这不是需要,也可以await 两次。两者都会做同样的事情。这当然是一种合适的方法。在 C# 5.0 中,您实际上可以将 Unwrap 实现为:public static async Task Unwrap(this Task&lt;Task&gt; task){ await await task; }(C# 4.0 版本实际上非常冗长乏味。)
    • 请注意,您的第二个 sn-p 并不严格等同于 OP 的代码。他的代码有一个竞争条件,允许12 以任一顺序发生。您的第二个 sn-p 强制执行严格的排序。 (或者换一种说法,它不会并行化 OP 并行化的一些操作,并且可能是他希望这两个操作能够并行发生。
    • @Servy 你说得对,我假设他想要简化的案例。可能不是这样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多