Я опаздываю на вечеринку, но вот мое учебное путешествие по этой хитрой теме.
1. Где мы можем найти официального адвоката по повторному использованию HttpClient?
Я имею в виду, что если повторное использование HttpClient предназначено
и это важно , то такой адвокат лучше задокументирован в собственной документации API, а не скрыт во множестве «Расширенных тем», «Производительных (анти) шаблонов» или других постов в блоге. , Иначе как новый ученик должен знать это, пока не стало слишком поздно?
На данный момент (май 2018 г.) первый результат поиска при поиске в Google «c # httpclient» указывает на эту справочную страницу API в MSDN , которая вообще не упоминает об этом намерении. Итак, урок 1 для новичка: всегда нажимайте ссылку «Другие версии» сразу после заголовка страницы справки MSDN, там вы, вероятно, найдете ссылки на «текущую версию». В этом случае HttpClient, он приведет вас к последнему документу,
содержащему описание этого намерения .
Я подозреваю, что многие разработчики, которые были новичками в этой теме, также не нашли правильную страницу документации, поэтому эти знания не получили широкого распространения, и люди были удивлены, когда узнали об этом
позже , возможно, с трудом .
2. Понятие (не так?) using
IDisposable
Это одна немного не по теме , но все же стоит отметить, что это не совпадение , чтобы увидеть людей в тех вышеупомянутых блогах обвиняющих как HttpClient
«S IDisposable
интерфейс делает их , как правило , использовать using (var client = new HttpClient()) {...}
шаблон , а затем привести к этой проблеме.
Я полагаю, что это сводится к негласной (ошибочной?) Концепции:
«ожидается, что IDisposable объект будет недолговечным» .
ОДНАКО, хотя это, конечно, выглядит недолгим, когда мы пишем код в этом стиле:
using (var foo = new SomeDisposableObject())
{
...
}
официальная документация по IDisposable
никогда не упоминает IDisposable
объекты должны быть кратковременными. По определению, IDisposable - это просто механизм, позволяющий вам высвобождать неуправляемые ресурсы. Ничего больше. В этом смысле вы ОЖИДАЕТЕ в конечном итоге инициировать утилизацию, но это не требует, чтобы вы делали это недолгим образом.
Поэтому ваша задача - правильно выбрать, когда инициировать утилизацию, исходя из требований жизненного цикла вашего реального объекта. Ничто не мешает вам использовать IDisposable в течение длительного времени:
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine("Hello World!");
using (var client = new HttpClient())
{
for (...) { ... } // A really long loop
// Or you may even somehow start a daemon here
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
С этим новым пониманием, теперь, когда мы возвращаемся к этому сообщению в блоге , мы можем четко заметить, что «исправление» инициализируется HttpClient
один раз, но никогда не удаляет его, поэтому мы можем видеть из его вывода netstat, что соединение остается в состоянии ESTABLISHED, что означает, что оно имеет НЕ был правильно закрыт. Если бы он был закрыт, его состояние было бы в TIME_WAIT. На практике нет ничего страшного в том, чтобы утратить только одно открытое соединение после завершения всей вашей программы, и постер блога все еще видит увеличение производительности после исправления; но все же, концептуально неправильно обвинять IDisposable и выбирать НЕ распоряжаться им.
3. Нужно ли нам помещать HttpClient в статическое свойство или даже в качестве одиночного?
Исходя из понимания предыдущего раздела, я думаю, что ответ здесь становится ясным: «не обязательно». Это действительно зависит от того, как вы организуете свой код, если вы повторно используете HttpClient И (в идеале) утилизируете его в конце концов.
Весело, что даже пример в разделе «
Замечания» текущего официального документа
не делает это строго правильно. Он определяет класс «GoodController», содержащий статическое свойство HttpClient, которое не будет утилизироваться; что не подчиняется тому, что
подчеркивает другой пример в разделе «Примеры» : «необходимо вызвать dispose ... чтобы приложение не теряло ресурсы».
И, наконец, синглтон не без собственных проблем.
«Сколько людей считают глобальную переменную хорошей идеей? Никто.
Сколько людей считают синглтон хорошей идеей? Несколько.
Что дает? Синглтоны - это просто набор глобальных переменных ".
- Цитируется из этой вдохновляющей лекции "Глобальное государство и синглтоны"
PS: SqlConnection
Этот вопрос не имеет отношения к текущим вопросам и ответам, но, вероятно, его следует знать. Схема использования SqlConnection отличается. Вам НЕ нужно повторно использовать SqlConnection , потому что он будет лучше обрабатывать свой пул соединений.
Разница обусловлена их подходом к реализации. Каждый экземпляр HttpClient использует свой собственный пул соединений (цитируется
здесь ); но сам SqlConnection управляется центральным пулом соединений, в соответствии с этим .
И вам все еще нужно избавиться от SqlConnection, так же, как вы должны делать для HttpClient.