c# - 调用 API 20 次来生成列表,最佳实践?

标签 c# asynchronous concurrency parallel-processing .net-4.6

情况是,我调用一次 API 来获取租户列表,然后对于每个租户,我必须再次调用以获取租户的使用情况列表。遗憾的是,无法通过一次调用获取所有租户的使用情况。

现在我希望尝试通过使这些调用并发来节省时间。然后在最后一个到达后将它们全部放在一起。到目前为止,我的尝试如下:

public async Task<List<Usage>> GetUsagesAsync2(Task<List<Tenant>> tenants)
{
    List<Usage> usages = new List<Usage>();

    foreach (var tenant in await tenants)
    {
        //Generate request
        RestRequest request = new RestRequest("tenants/{tenantID}/usages", Method.Get);
        request.AddParameter("tenantID", tenant.id, ParameterType.UrlSegment);
        request.AddHeader("Authorization", $"Bearer {Token.access_token}");

        //Get response
        RestResponse response = await _client.ExecuteAsync(request)
            .ConfigureAwait(false);

        //Validate response
        if (response.StatusCode != HttpStatusCode.OK)
            throw new Exception("Failed at Getting usages for a tenant: ");

        //Add to list
        var t_usage = JsonConvert.DeserializeObject<Wrapper<Usage>>(response.Content);
        usages.AddRange(t_usage.items);
    }
    return usages;
}

代码运行并执行预期的操作,但我不确定它实际上是异步运行的。运行大约需要 7-8 秒,我发现在网页上等待的时间有点长。

最佳答案

这是并行实现:

.NET 6

public async Task<ConcurrentBag<Usage>> GetUsagesAsync2(Task<List<Tenant>> tenants)
{
    ConcurrentBag<Usage> usages = new ConcurrentBag<Usage>();

    await Parallel.ForEachAsync(await tenants, async (tenant) =>
    {
        //Generate request
        RestRequest request = new RestRequest("tenants/{tenantID}/usages", Method.Get);
        request.AddParameter("tenantID", tenant.id, ParameterType.UrlSegment);
        request.AddHeader("Authorization", $"Bearer {Token.access_token}");

        //Get response
        RestResponse response = await _client.ExecuteAsync(request).ConfigureAwait(false);

        //Validate response
        if (response.StatusCode != HttpStatusCode.OK)
            throw new Exception("Failed at Getting usages for a tenant: ");

        //Add to list
        var t_usage = JsonConvert.DeserializeObject<Wrapper<Usage>>(response.Content);
        usages.AddRange(t_usage.items);
    });

    return usages;
}

.Net 6 之前的版本

public async Task<ConcurrentBag<Usage>> GetUsagesAsync2(Task<List<Tenant>> tenants)
{
    ConcurrentBag<Usage> usages = new ConcurrentBag<Usage>();
    var tasks = new List<Task>();

    foreach (var tenant in await tenants)
    {
        tasks.Add(Task.Run(async () =>
        {
            //Generate request
            RestRequest request = new RestRequest("tenants/{tenantID}/usages", Method.Get);
            request.AddParameter("tenantID", tenant.id, ParameterType.UrlSegment);
            request.AddHeader("Authorization", $"Bearer {Token.access_token}");

            //Get response
            RestResponse response = await _client.ExecuteAsync(request)
                .ConfigureAwait(false);

            //Validate response
            if (response.StatusCode != HttpStatusCode.OK)
                throw new Exception("Failed at Getting usages for a tenant: ");

            //Add to list
            var t_usage = JsonConvert.DeserializeObject<Wrapper<Usage>>(response.Content);
            usages.AddRange(t_usage.items);
        }));
    }

    await Task.WhenAll(tasks);

    return usages;
}

请注意,List 已更改为 ConcurrentBag,因为它不是线程安全的

关于c# - 调用 API 20 次来生成列表,最佳实践?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73277096/

相关文章:

javascript - 加载 gtm.js 时网页闪烁

java - 如何同时进行多个jsoup session (Spring boot项目和并发)

c# - 使用 XPATH 从 XML 文档中选择特定值?

C# 如何创建日期和时间范围?

javascript - 在 react 组件挂载之前加载 cms 内容

c# - 如何使用 async/await 查找 'hangs' 的哪个方法?

dictionary - 如何清除sync.Map

c++ - waitpid() 和 fork() 限制子进程的数量

C# 使用 linq 将列转换为行?

c# - 所有好友列表 C# Facebook SDK v5