簡體   English   中英

調用 API 20 次以生成列表,最佳實踐?

[英]Calling an API 20 times to generate a list, best practice?

案例是我調用一次 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;
}

預網 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因為它不是線程安全的

你基本上可以做的是:

IEnumerable<Task<List<Usage>> loadTasks = tenants.Select(LoadUsages);
List<Usage>[] usages = await Task.WhenAll(loadTasks);

async Task<List<Usage>> LoadUsages(Tenant t) {
    // your web call goes here
    return t_usage.items;
}

但是,正如評論中所指出的,這不會受到限制,並且可能一次發出太多請求。 如果您確定租戶數量將保持在 20 左右,那應該沒問題。 否則,您將不得不實施更復雜的批處理解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM