Почему c # Parallel.ForEach не создает слишком много открытых соединений в моем приложении c #? - PullRequest
0 голосов
/ 19 февраля 2019

У меня были некоторые проблемы в коде, из-за которых слишком много открытых соединений, что приводило к их закрытию и отсутствию 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 есть оптимизация для создания наилучшего количества задачи это может как-то сработать, что это вызовет слишком много открытых соединенийили слишком много работы процессора?

1 Ответ

0 голосов
/ 19 февраля 2019

Вы получаете доступ к внешнему ресурсу (через http-клиент) - операции ввода-вывода, для этого и был разработан 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 вы сможете отправлять все запросы, не ожидая ответов.
А когда все ответы успешно получены, вы можете приступить к обработке полученных данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...