C# foreach循环迭代中的多个异步/等待调用

C# foreach循环迭代中的多个异步/等待调用,c#,asynchronous,foreach,async-await,C#,Asynchronous,Foreach,Async Await,我正试图了解如何在foreach循环中处理多个异步/等待调用。我有大约20000行数据,这些数据由foreach循环处理。我的代码大致如下: foreach (var item in data) { if (ConditionA(item)) { if (ConditionAB(item)); { await CreateThingViaAPICall(item) } else

我正试图了解如何在foreach循环中处理多个异步/等待调用。我有大约20000行数据,这些数据由foreach循环处理。我的代码大致如下:

foreach (var item in data)
{
    if (ConditionA(item))
    {
        if (ConditionAB(item));
        {
            await CreateThingViaAPICall(item)
        }
        else
        {
            var result = await GetExistingRecord(item);
            var result2 = await GetOtherExistingRecord(result);
            var result3 = await GetOtherExistingRecord(result2);
            //Do processing
            ...           
            await CreateThingViaAPICall();
        }
    }
    ... and so on        
}
我看到很多帖子说,在循环中使用异步的最佳方法是构建一个任务列表,然后使用Task.WhenAll。在我的例子中,作为每个迭代的一部分,我有相互依赖的任务。在这种情况下,如何建立要执行的任务列表


如果我没有弄错的话,建议在foreach中使用async/wait的方法是首先构建一个任务列表,然后调用Task.WhenAll

你错了一部分

如果您有一个相互不依赖的多个任务,那么将这些多个任务安排在一个
时间段内,这样它们就可以一起调度,从而提供更好的吞吐量,这通常是一个非常好的主意

然而,如果每个任务都取决于前一个任务的结果,那么这种方法是不可行的。相反,您应该在
foreach
中等待它们

事实上,这在任何情况下都会很好地工作,如果任务不需要互相等待,那么让任务互相等待是次优的


foreach
中等待
任务的能力实际上是
async
/
await
给我们的最大好处之一。大多数使用
wait
的代码可以很容易地重新编写为使用
ContinueWith
,如果不那么优雅,但是循环更复杂,如果只通过检查任务本身的结果才能找到循环的实际末端,那么再复杂一次。

如果将单个项目的处理分解为单独的项目,这是最简单的(异步)方法:

然后像这样处理您的收藏:

var tasks = data.Select(ProcessItemAsync);
await Task.WhenAll(tasks);
这有效地将处理单个项所需的多个依赖任务包装到一个任务中,允许这些步骤在同时处理集合本身的项时按顺序进行


对于成千上万的项目,出于各种原因,您可能会发现需要限制并发运行的任务数量。请查看此类场景的TPL数据流。例如,请参阅。

您所拥有的有什么问题?如果我没有弄错,建议在foreach中使用async/wait的方法是构建一个list of Tasks首先调用Task.WhenAll。我的问题是循环的每个迭代都有多个相互依赖的任务。在这种情况下,我如何建立等待的任务列表?我是否误解了您的问题?迭代中的每个项目是否依赖于前一个项目的成功完成?迭代中的每个项目都依赖于你的答案真的很有帮助,我只是可以选择两者作为答案。啊,好吧,然后我做了一个错误的假设。我不是想刷接受的答案,但我很高兴它是有帮助的:)所以建议使用Task.whalll是一个性能相关的建议,不是“如果你这样做,会发生坏事”的建议吗?是的。现在,当它适用时,它会产生很大的不同,所以当你可以的时候,一定要采取这种方法。你甚至可以做一个混合动力车;任务块中的每个任务块相互依赖,但每个任务块可以独立。好吧,这很有意义,再加上@jon hanna的回答就更有意义了。我理解你的问题的方式是,项目a和项目B可以同时处理,但处理单个项目所涉及的步骤必须按顺序进行。这就是这种方法给你的。
var tasks = data.Select(ProcessItemAsync);
await Task.WhenAll(tasks);