2017-10-17 80 views
3

我正在寫一個方法,接受ID列表來調用API。 該API有一個限制,一次只能接受1000個ID。所以我需要將列表拆分爲塊並分別進行調用。C#發佈ID塊和合並響應使用異步和等待

public async Task<List<JObject>> readData(List<int> IDs){ 
    const int APIMaxLimit = 1000; 
    List<List<int>> chunks = new List<List<int>>(); 
    while (IDs.Any()) 
    { 
     chunks.Add(IDs.Take(APIMaxLimit).ToList()); 
     IDs= IDs.Skip(APIMaxLimit).ToList(); 
    } 
    var apiCallTasks = new List<Task>(); 
    foreach (var chunk in chunks) 
    { 
     //some logic 
     apiCallTasks.Add(ReadDatacentersFromResponse(response)); 
    } 

    await Task.WhenAll(apiCallTasks); 

    //What do I return? 

} 

private static async Task<List<JObject>> ReadDatacentersFromResponse(HttpResponseMessage response); 

我寫了上面的代碼,但我不知道如何返回組合值。另外,有沒有辦法編寫更優雅的代碼而不使用for循環?

+2

@zzxyz我真的沒有看到任何超級複雜的問題。當它使用'async' /'await'時,他需要的答案與它沒有直接關係。它可以簡化爲將一系列數字分成批次,然後重新組合,而不會發生太大的變化。 –

+0

@zzxyz,似乎有點下意識,對我毫無幫助。 OP不需要做任何「'Run()'調用」來使他/她的代碼工作。他/她對如何將他/她正在等待的任務的結果與「Task.WhenAll」調用相結合有一個合理的問題。 –

+0

他不?他的任務會自動運行?我錯過了什麼?我猜測問題是他不知道如何檢查任務的返回值。如果這不是問題,請使用'.AddRange()'。完成。我並不想成爲一個混蛋,只是說像這樣的問題不是學習異步模式的好地方。 Web服務器可能關閉,或者其他一百個問題之一可能會使問題複雜化。 – zzxyz

回答

4

從一般觀點來看,您可以使用.SelectMany將多個IEnumerable組合回單個IEnumerable

var data = new List<List<int>> 
    { 
     new List<int>{1,2,3}, 
     new List<int>{4,5,6}, 
     new List<int>{7,8,9} 
    }; 

var result = data.SelectMany(x => x); 

返回:{1, 2, 3, 4, 5, 6, 7, 8, 9}


在你的具體的例子,你可能需要改變

var apiCallTasks = new List<Task>(); 

var apiCallTasks = new List<Task<List<JObject>>>(); 

允許您訪問Result每一個人Task的財產,並與合併後返回的結果:

apiCallTasks.SelectMany(r2 => r2.Result); 
0

這裏是另一種答案,但我更喜歡布拉德利的。儘管我使用ints而不是JObjects,但它是一個簡單的完整示例。如果性能是一個問題,你可以看看ArraySegment。我們的解決方案都不是特別快。

private async Task<List<int>> ReturnInts() 
    { 
     return new List<int> { 5 }; 
    } 

    public async Task<List<int>> PenanceFunction() 
    { 
     List<Task<List<int>>> tasks = new List<Task<List<int>>>(); 
     tasks.Add(ReturnInts()); 
     tasks.Add(ReturnInts()); 
     List<int> myResults = new List<int>(); 
     await Task.WhenAll(tasks); 
     foreach(var t in tasks) 
     { 
      myResults.AddRange(t.Result); 
     } 
     return myResults; 
    }