首页 > 解决方案 > 将项目异步添加到 foreach 循环中的列表

问题描述

我有一个循环,它从 3rd 方 API 检索对象(因此我必须一次请求每个对象)并将它们添加到一个列表中,然后我从我的过程中返回。它目前按顺序执行这些操作,但我希望循环是异步的以提高性能。

基本代码如下所示:

public async Task<List<ResponseObject<MyClass>>> GetMyClass(string[] references)
    {
        var responseObject = new ResponseObject<MyClass>();
        var responseObjects = new List<ResponseObject<MyClass>>();

            foreach (var reference in references)
            {
                responseObject = await GetExternalData(reference);
                responseObjects.Add(responseObject);
            }

        return responseObjects;
    }

我调用的方法定义如下:

public async Task<ResponseObject<MyClass>> GetExternalData(string reference)

我需要如何更改它以使其打开相同的 ReponseObjects 列表,并以并行而不是顺序加载它们?任何帮助将不胜感激。

标签: c#asynchronousforeach

解决方案


尝试这样做.Select

public async Task<List<ResponseObject<MyClass>>> GetMyClass(string[] references)
{
    var responseObject = new ResponseObject<MyClass>();
    var responseObjects = new ConcurrentBag<ResponseObject<MyClass>>();

    var tasks = references.Select(async item => 
    {
        var responseObject = await GetExternalData(item);
        responseObjects.Add(responseObject);
    });

    await Task.WhenAll(tasks);

    return responseObjects.ToList();
}

还有一个AsyncEnumerator NuGet 包,其中包含一个ParallelForEachAsyncParallel.ForEach. references如果可以有很多对象,我会建议使用这种方法。如上所述,这将产生尽可能多的任务references。使用ParallelForEachAsync你可以控制并行度以避免过多的请求,它看起来像这样:

public async Task<List<ResponseObject<MyClass>>> GetMyClass(string[] references)
{
    var responseObject = new ResponseObject<MyClass>();
    var responseObjects = new ConcurrentBag<ResponseObject<MyClass>>();

    await references.ParallelForEachAsync(async item =>
    {
        var responseObject = await GetExternalData(item);
        responseObjects.Add(responseObject);   
    }, maxDegreeOfParallelism: 8);

    return responseObjects.ToList();
}

推荐阅读