嵌套Task.WhenAll有什么限制吗?

Kon*_*tko 5 .net c# parallel-processing async-await

让我们想象一些抽象代码

    private void Main()
    {
        var workTask1 = DoWork1();
        var workTask2 = DoWork2();
        var workTask3 = DoWork3();

        await Task.WhenAll(workTask1, workTask2, workTask3);

        AnalyzeWork(workTask1.Result, workTask2.Result, workTask3.Result);
    }

    private async Task<object> DoWork1()
    {
        var someOperationTask1 = someOperation1();
        var someOperationTask2 = someOperation2();

        await Task.WhenAll(someOperationTask1, someOperationTask2);

        return new object
        {
            SomeOperationResult1 = someOperationTask1.Result,
            SomeOperationResult2 = someOperationTask2.Result,
        };
    }

    private async Task<object> DoWork2()
    {
        var someOperationTask3 = someOperation3();
        var someOperationTask4 = someOperation4();

        await Task.WhenAll(someOperationTask3, someOperationTask4);

        return new object
        {
            SomeOperationResult3 = someOperationTask3.Result,
            SomeOperationResult4 = someOperationTask4.Result,
        };
    }

    private async Task<object> DoWork3()
    {
        var someOperationTask5 = someOperation5();
        var someOperationTask6 = someOperation6();

        await Task.WhenAll(someOperationTask5, someOperationTask6);

        return new object
        {
            SomeOperationResult5 = someOperationTask5.Result,
            SomeOperationResult6 = someOperationTask6.Result,
        };
    }
Run Code Online (Sandbox Code Playgroud)

其中 3 个方法并行运行,每个方法都包含 2 个并行操作。3 个方法的结果被传递给某个方法。

我的问题是有什么限制吗?可以嵌套 Task.WhenAll 吗?嵌套 Task.WhenAll 和一级 Task.WhenAll 操作之间有什么区别?

The*_*ias 3

唯一的限制是系统的可用内存。该Task.WhenAll方法将延续附加到每个未完成的任务,并且在该任务完成时分离该延续。延续是类似于 的轻量级对象Task。它与调用该Task.ContinueWith方法时得到的结果非常相似。每个延续的权重大约为 100 字节。它不太可能对您的程序产生任何明显的影响,除非您需要Task.WhenAll同时处理数千万个(或更多)任务。

如果您想直观地演示该方法的内部结构,下面是其实现的粗略草图:

// For demonstration purposes only. This code is full of bugs.
static Task WhenAll(params Task[] tasks)
{
    var tcs = new TaskCompletionSource();
    int completedCount = 0;
    foreach (var task in tasks)
    {
        task.ContinueWith(t =>
        {
            completedCount++;
            if (completedCount == tasks.Length) tcs.SetResult();
        });
    }
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)