C#发布ID块和合并响应使用异步和等待

问题描述:

我正在写一个方法,接受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

从一般观点来看,您可以使用.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); 

这里是另一种答案,但我更喜欢布拉德利的。尽管我使用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; 
    }