【问题标题】:What is the order of the task result when using WhenAll and ContinueWith使用WhenAll和ContinueWith时任务结果的顺序是什么
【发布时间】:2016-02-03 11:41:48
【问题描述】:

只想知道使用WhenAll和ContinueWith时任务结果的顺序。 这些结果是否与任务 ID 的顺序相同?

我写了下面的代码

public static async Task<string> PrintNumber(int number)
{
    return await Task.Delay(number*1000).ContinueWith(_=>
    {
        Console.WriteLine(number);return "TaskId:"+Task.CurrentId+" Result:"+number;
    });
}

public static void Main()
{

    Task.WhenAll(new[]
    {
        PrintNumber(3),
        PrintNumber(2),
        PrintNumber(1),

    }).ContinueWith((antecedent) => 
    { 
        foreach(var a in antecedent.Result)
        {
            Console.WriteLine(a);
        }
    });
}

并在 linqpad 中运行几次得到相同的结果

1
2
3
TaskId:15 Result:3
TaskId:14 Result:2
TaskId:13 Result:1

1
2
3
TaskId:18 Result:3
TaskId:17 Result:2
TaskId:16 Result:1

【问题讨论】:

    标签: c# asynchronous task-parallel-library


    【解决方案1】:

    对于特定的调用,Task[] 的参数 - 顺序是保证的。

    事实上,根据Task.WhenAll(Task[]) 文档,根本没有提到顺序。但如果你使用 Task.WhenAll(IEnumerable&lt;Task&lt;TResult&gt;&gt;) 重载,它会读取为follows

    如果没有任务出错并且没有任务被取消,则生成的任务将以 RanToCompletion 状态结束。返回任务的 Result 将设置为一个数组,其中包含所提供任务的所有结果与提供的顺序相同(例如,如果输入任务数组包含 t1、t2、t3、输出任务的 Result 将返回一个 TResult[],其中 arr[0] == t1.Result, arr1 == t2.Result, and arr[2] == t3.Result)。

    【讨论】:

    • 感谢@David,只需通过 reshaper 反编译 whenAll,whenAll(tasks[]) 和 WhenAll(IEnumerable> tasks) 应该相同。又名。结果的顺序也应与提供的顺序相同
    • 很接近,但存在可能影响该保证的差异。我的回答专门基于文档。
    【解决方案2】:

    当您调用Task.WhenAll(使用可枚举或参数数组)时,结果的顺序与传递给该方法的任务的顺序相匹配。

    也就是说,这是真的:

    var task1 = PrintNumber(3);
    var task2 = PrintNumber(2);
    var task3 = PrintNumber(1);
    var taskResults = await Task.WhenAll(task1, task2, task3);
    // taskResults[0] is the same as task1.Result
    // taskResults[1] is the same as task2.Result
    // taskResults[2] is the same as task3.Result
    

    但是,ContinueWith 是一个完全不同的故事。 ContinueWith 附加一个延续,这个延续将在任务完成后的某个时间运行。

    在您的特定代码中,您将延续附加到传递给Task.WhenAll 的任务。但如果你是,那么在该任务完成后的任何时候都可以继续运行。

    顺便说一句,don't use ContinueWith(正如我在博客中解释的那样)。只需改用await;生成的代码更正确、更简洁、更易于维护。

    【讨论】:

    • 谢谢@Stephen Cleary,我想我明白你的回答。也就是说,如果我将ContinueWith附加到task1,task2,task3,则无法保证ContinueWith中代码的执行顺序。另外,我相信task1,task2,task3也不应该按照传入的任务顺序
    • @ValidfroM:是的,如果您将延续附加到task1,那么await Task.WhenAll 可能会在延续运行之前完成(或在运行时)。但是,Task.WhenAll 任务的结果按照传递给Task.WhenAll 的任务的顺序排列。结果将始终按 1、2、3 的顺序排列;这是有保证的。是否附加延续并不重要。
    猜你喜欢
    • 2018-03-10
    • 1970-01-01
    • 2017-12-03
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    相关资源
    最近更新 更多