Я спізнююсь на вечірку, але ось моя навчальна подорож на цю складну тему.
1. Де можна знайти офіційного захисника щодо повторного використання HttpClient?
Я маю на увазі, якщо планується повторне використання HttpClient,
і це важливо , такий адвокат краще задокументувати у власній документації API, а не ховати у багатьох "Розширених темах", "Ефективності (анти) шаблоні" чи інших публікаціях у блозі . Інакше як новий студент повинен знати це ще до того, як пізно?
На сьогодні (травень 2018 р.) Перший результат пошуку, коли googling "c # httpclient" вказує на цю довідкову сторінку API в MSDN , яка взагалі не згадує про цей намір. Ну, урок 1 для новачків - завжди натискайте посилання "Інші версії" відразу після заголовка довідкової сторінки MSDN, ви, ймовірно, знайдете там посилання на "поточну версію". У цьому випадку HttpClient він перенесе вас до останнього документа,
що містить опис цього наміру .
Я підозрюю, що багато розробників, які були новими в цій темі, також не знайшли правильної сторінки документації, тому ці знання не отримали широкого поширення, і люди були здивовані, коли дізналися про це
пізніше , можливо, важким способом .
2. Помилкове поняття using
IDisposable
Це одна трохи не по темі , але все ж варто відзначити, що це не збіг , щоб побачити людей в тих вищезгаданих блогах звинувачують як HttpClient
«s IDisposable
інтерфейс робить їх , як правило , використовувати using (var client = new HttpClient()) {...}
шаблон , а потім привести до цієї проблеми.
Я вважаю, що це зводиться до невисловленого (неправильного?) Поняття:
"Очікується, що об'єкт, що не має доступу, буде короткочасним" .
ЗАРАЗ, хоча це, звичайно, виглядає як недовговічна річ, коли ми пишемо код у такому стилі:
using (var foo = new SomeDisposableObject())
{
...
}
в офіційній документації на 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, що з'єднання залишається у встановленому стані, що означає, що воно має НЕ було належним чином закрито. Якби він був закритий, його стан був би замість TIME_WAIT. На практиці не дуже важливо протікати лише одне підключення після закінчення всієї вашої програми, а блог-плакат все ще бачить підвищення продуктивності після виправлення; але все-таки, концептуально неправильно звинувачувати IDisposable і вирішити НЕ розпоряджатися ним.
3. Чи потрібно ставити HttpClient у статичну властивість чи навіть ставити його як синглтон?
Виходячи з розуміння попереднього розділу, я думаю, що відповідь тут стає зрозумілою: "не обов'язково". Це дійсно залежить від того, як ви впорядковуєте свій код, доки ви повторно використовуєте HttpClient І (в ідеалі) розпоряджаєтесь ним з часом.
Весело, що навіть приклад у розділі «
Зауваження» цього офіційного документа
не робить це суворо правильно. Він визначає клас "GoodController", що містить статичну властивість HttpClient, яка не розпоряджається; що не дотримується того, що
підкреслює інший приклад у розділі Приклади : "потрібно викликати розпорядження ... щоб додаток не просочував ресурси".
І, нарешті, одиночний не без власних викликів.
"Скільки людей вважають глобальну змінну гарною ідеєю? Ніхто.
Скільки людей думають, що одиночна справа - це гарна ідея? Декілька.
Що дає? Синглтони - це лише купа глобальних змінних ".
- Цитується з цієї натхненної бесіди "Глобальна держава та одинаки"
PS: SqlConnection
Цей питання не має значення для нинішніх запитань, але це, мабуть, добре знати. Шаблон використання SqlConnection відрізняється. Ви НЕ повинні повторно використовувати SqlConnection , тому що він буде обробляти свій пул з'єднань краще.
Різниця зумовлена їх підходом до реалізації. Кожен екземпляр HttpClient використовує власний пул з'єднань (цитується
звідси ); але сам SqlConnection управляється центральним пулом з'єднань, відповідно до цього .
І вам все-таки потрібно розпоряджатися SqlConnection так само, як ви повинні зробити для HttpClient.