Лучший способ приостановить цикл с помощью внутреннего асинхронного вызова в C # - PullRequest
0 голосов
/ 17 апреля 2019

Я отправляю список из примерно 100 000 объектов JSON в API, который может принимать их только один за другим, и я отправляю их асинхронно.Я знаю, что внутренне API отправляет полученный объект в очередь, которая, похоже, блокируется всеми этими запросами, в результате чего я получаю сообщение об ошибке «Тайм-аут шлюза» после нескольких из них.

Я пыталсяРазбиение списка партиями разных размеров и перевод потока в спящий режим после отправки каждой партии, но в итоге происходит сбой с той же ошибкой примерно с размером пакета, я пробовал с партиями 3000, 2500и 1000 с одинаковым результатом, и поток, кажется, никогда не засыпает.

Вот код, о котором идет речь:

public async Task TransferData(IEnumerable<MyData> data)  
{  
     var pages = Math.Ceil(data.Count() / 3000m);  

     for (var page = 0; page < pages; page++)  
     {  
         await TransferPage(data.Skip(page * 3000).Take(3000);
         Thread.Sleep(10000);  
     }  
}

private async Task TransferPage(IEnumerable<MyData> data)  
{  
     await Task.WhenAll(data.Select(p => webConnection.PostDataAsync(JsonConvert.SerializeObject(p, Formatting.None))));  
}

Примечание: webConnection - это просто класс, имеющийHttpClient уже создан и выполняет PostAsync для данных по намеченному URL.

Вызов TransferData выполняется в консольном приложении следующим образом:

try  
{  
   ...    
   dataManager.TransferData(data).Wait();
}
catch(AggregateException ex)
{
   ...
}
catch(Exception ex)
{
   ...
}

Спасибо за любыеруководство.

ОБНОВЛЕНИЕ: Чтобы прояснить некоторую путаницу, возникшую в комментариях.Внешний API получает объекты один за другим, , если вы посмотрите на закрытый метод TransferPage внутри WhenAll, IEnumerable имеет метод Select с вызовом метода, который внутренне выполняет фактический HttpClient PostAsync.Таким образом, объекты группируются по партиям, и в каждом пакете они отправляются по одному.Надеюсь, это немного прояснит ситуацию.

1 Ответ

0 голосов
/ 17 апреля 2019

Вероятно, что одна или несколько задач PostDataAsync выбрасывают ошибку тайм-аута, что приводит к сбою задачи.Task.WhenAll только объединяет их в AggregateException и выбрасывает его после завершения всех задач в списке, поэтому вы видите исключение только в конце пакета.

Вы, вероятно, подавляетеобслуживание, несмотря на вашу попытку газа.Вероятно, вам следует сделать пару вещей:

  • Улучшить обработку исключений и повторить попытку.Вы можете сделать это внутри PostDataAsync и / или вне его.Даже если вы не перегружаете службу, вам все равно придется обрабатывать временные исключения, чтобы справиться с сбоями в работе сети и т. П.
  • Замените логику пакетной обработки правильной реализацией регулирования.Хороший старт - ответы на вопрос, который Серг связал в комментариях, - SemaphoreSlim или TPL Dataflow - общие решения.
...