使用Async列出<t> .ForEach()的任何一点?

时间:2015-08-11 17:28:35

标签: c# asynchronous async-await

我遇到了这段代码:

items.ForEach(async item =>
{
     doSomeStuff();   
     await mongoItems.FindOneAndUpdateAsync(mongoMumboJumbo);
     await AddBlah(SqlMumboJumbo);
});

将这个.forEach委托制作成是否有任何意义,或者它只是一个正常的foreach循环?只要包含循环的函数是异步的,默认情况下这是异步的吗?

2 个答案:

答案 0 :(得分:7)

ForEach收到的代表是Action<T>

public void ForEach(Action<T> action)

这意味着,您在其中使用的任何异步委托都将有效地转换为async void方法。这些是“火与忘记”。执行方式。这意味着你的foreach不会在继续调用列表中下一个项目的委托之前完成异步等待,这可能是一个不受欢迎的行为。

改为使用常规foreach

旁注 - Eric Lippert撰写的foreach VS ForEach,很棒的博文。

答案 1 :(得分:2)

您不知道您的功能何时结束,也不知道该功能的结果。如果您在单独的任务中开始每个计算,您可以等待Task.WhenAll并解释结果,甚至捕获异常:

private async Task ActionAsync(T item)
{
    doSomeStuff();   
    await mongoItems.FindOneAndUpdateAsync(mongoMumboJumbo);
    await AddBlah(SqlMumboJumbo);
}

private async Task MyFunction(IEnumerable<T> items)
{
    try
    {
        foreach (var item in items)
        {
            tasks.Add( ActionAsync(item) )
        }
        // while all actions are running do something useful
        // when needed await for all tasks to finish:
        await Task.WhenAll(tasks);
        // interpret the result of each action using property Task.Result
    }
    catch (AggregateException exc)
    {
        ProcessAggregateException(exc);
    }
}

当任何任务抛出异常时,抛出aggregateException。如果包含所有任务抛出的所有异常。