我的代码中存在一些问题,导致打开的连接过多,导致它们关闭并且没有http响应。此后,我将其重构为如下所示:
List<<List<string>> batches = splitListOfUrlStringsIntoBatches(urls, 50); // where 50 is the batch size
然后我做
:foreach (var batchList in listOfBatchLists)
{
var insertForBatch = RunBatch(batchList);
allInsertAmounts.Add(insertForBatch);
}
并运行批处理如下:
private int RunBatch(IEnumerable<string> batch)
{
var allWriteNum = 0;
// this will run on one bound logical thread i think
Parallel.ForEach(batch, (batchItem) => {
var res = Client.GetAsync(batchItem.Item1).GetAwaiter().GetResult();
var responseBody = res.Content.ReadAsStringAsync().GetAwaiter().GetResult();
var strongType = JsonConvert.DeserializeObject<StrongType>(responseBody);
dbContext.add(strongType);
allWriteNum++
});
return allWriteNum;
}
问题是,如果我将批次大小增加到50,000之类的愚蠢值,我没有收到任何关闭的连接错误,现在我不确定为什么。
是因为Parallel.foreach进行了优化以创建最佳数量的任务,并且可以以某种方式确定这样做会导致太多打开的连接吗?或太多的CPU工作?
答案 0 :(得分:2)
您正在(通过http客户端)访问外部资源-IO操作,这是async-await设计的目的。
public async Task<StrongType> GetAsync(Item item)
{
var response = await Client.GetAsync(item);
var body = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<StrongType>(body);
}
public async Task Run(IEnumerable<Item> items)
{
var tasks = items.Select(item => GetAsync(item));
await Task.WhenAll(tasks);
var loadedStrongTypes = tasks.Select(task => task.Result);
dbContext.AddRange(loadedStrongTypes);
}
因为代码使用外部资源,所以并行方法将通过创建许多无所事事的线程(仅等待响应)来浪费资源。
使用async-await,您将能够发送所有请求而无需等待响应。
当所有响应成功到达后,您可以继续处理接收到的数据。