为什么c#Parallel.ForEach在我的c#应用程序中没有创建太多打开的连接?

时间:2019-02-19 19:49:53

标签: c# .net-core parallel.foreach

我的代码中存在一些问题,导致打开的连接过多,导致它们关闭并且没有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工作?

1 个答案:

答案 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,您将能够发送所有请求而无需等待响应。
当所有响应成功到达后,您可以继续处理接收到的数据。