Безопасно ли использовать HttpClient одновременно?


151

Во всех примерах, которые я могу найти HttpClient, он используется для разовых вызовов. Но что, если у меня постоянная клиентская ситуация, когда несколько запросов могут быть сделаны одновременно? В принципе, безопасно ли вызывать client.PostAsync2 потока одновременно против одного и того же экземпляра HttpClient.

Я не очень ищу экспериментальные результаты здесь. В качестве рабочего примера может быть просто случайность (и при этом постоянная), а неудачный пример может быть проблемой неправильной конфигурации. В идеале я ищу какой-нибудь авторитетный ответ на вопрос обработки параллелизма в HttpClient.


2
Также прочитайте этот вопрос для получения дополнительной информации о том, как правильно его использовать HttpClientи утилизировать: stackoverflow.com/questions/15705092/…
Мани Гэндхэм

Ответы:


152

Согласно MSDN , начиная с .NET 4.5, следующие методы экземпляров являются потокобезопасными (спасибо @ischell):

CancelPendingRequests
DeleteAsync
GetAsync
GetByteArrayAsync
GetStreamAsync
GetStringAsync
PostAsync
PutAsync
SendAsync

3
Да, я не был уверен в этом, поскольку это стандартное предупреждение обо всем на MSDN (и я помню, как читал некоторые блоги MSDN о том, как иногда это предупреждение ошибочно, так как оно применяется вслепую ко всему).
Алекс К

3
Это не верно; в разделе замечаний на странице MSDN, на которую вы ссылаетесь, говорится, что все функции GetAsync, PostAsync и т. д. являются потокобезопасными.
Ишелл

4
@ischell: Я могу заверить вас, что рассматриваемый абзац отсутствовал на момент обсуждения этого вопроса.
Марсель Н.

7
Таким образом, Microsoft разработала HttpClient для повторного использования, но затем у класса есть данные экземпляра для заголовков: client.DefaultRequestHeaders.Accept.Add (...);
cwills

8
В конце, но я хотел прокомментировать @cwills. DefaultRequestHeaders - это просто настройки по умолчанию. Если вам нужны разные заголовки для каждого запроса, вы можете создать новый StringContent (), установить для него дополнительные заголовки, а затем использовать перегрузку, которая принимает URI и HttpContent.
Райан Андерсон

92

Вот еще одна статья Хенрика Ф. Нильсена о HttpClient, где он говорит:

« По умолчанию HttpClient - это самый простой способ начать отправку запросов. Один HttpClient может использоваться для одновременной отправки столько HTTP-запросов, сколько вы хотите, поэтому во многих сценариях вы можете просто создать один HttpClient, а затем использовать его для всех ваших запросов. . "


13
Что делать, если имя пользователя и пароль могут меняться между потоками? это то, о чем я не могу найти никого, о ком бы говорил
Николас ДиПиацца

1
@NicholasDiPiazza: как часто это меняется? Если существует известный набор пар пользователь / пароль, вы можете создать пул экземпляров HttpClient.
Марсель Н.

да, это то, что я в конечном итоге делал
Николас ДиПьяцца

2
Обратите внимание, что повторное использование одного и того же HttpClient для всех ваших запросов может привести к устаревшим проблемам DNS: github.com/dotnet/corefx/issues/11224 .
Охад Шнайдер

1
@OhadSchneider Если считаете, что проблема ограничена ядром .net. Вы можете решить проблему с .net 4, вставив пользовательский HttpClientHandler в конструктор HttpClient, а затем установив «ConnectionLeaseTimeout». Однако, если в течение 100 секунд в конечную точку не отправляются запросы, соединение будет обновлено само по себе. Защищенная задача переопределения <HttpResponseMessage> SendAsync (запрос HttpRequestMessage, CancellationToken cancellationToken) {var sp = ServicePointManager.FindServicePoint (request.RequestUri); sp.ConnectionLeaseTimeout = 100 * 1000; }
Тимоти Гонсалес

17

Нашел одно сообщение на форуме MSDN Хенрика Ф. Нильсена (одного из главных архитекторов HttpClient).

Краткое резюме:

  • Если у вас есть запросы, которые связаны (или не будут вступать друг в друга), тогда использование того же HttpClient имеет смысл.
  • В целом, я бы рекомендовал максимально использовать экземпляры HttpClient.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.