2016-10-08 3 views
3

Я запутался в асинхронных операциях ввода-вывода. В this article Стивен Клири объясняет, что мы не должны использовать Task.Run(() => SomeIoMethod()), потому что действительно асинхронных операций следует использоватьHttpClient предоставляет не действительно асинхронные операции?

стандарт P/Invoke асинхронная система ввода/вывода в .NET

http://blog.stephencleary.com/2013/11/there-is-no-thread.html

Однако, избегайте «поддельной асинхронности» в библиотеках. Фальшивая асинхронность - это когда компонент имеет API с асинхронным контентом, но он реализован только , обертывающий синхронный API в потоке пула потоков. То есть контрпродуктивная масштабируемость на ASP.NET. Одним из ярких примеров поддельной асинхронности является Newtonsoft JSON.NET, отличная библиотека . Лучше не называть (поддельные) асинхронные версии для сериализации JSON; просто вызовите синхронные версии. A более сложным примером поддельной асинхронности является поток файлов BCL. Когда открыт поток файлов , он должен быть явно открыт для асинхронного доступа ; в противном случае он будет использовать фальшивую асинхронность, синхронно блокируя поток потока потока в файле, который читает и записывает.

И он советует использовать HttpClient но internaly это использовать Task.Factory.StartNew() enter image description here

Означает ли это, что HttpClient обеспечивает действительно не асинхронные операции?

ответ

2

Означает ли это, что HttpClient обеспечивает не асинхронные операции?

Сорт. HttpClient находится в необычном положении, так как в его основной реализации используется HttpWebRequest, что составляет только частично асинхронный.

В частности, поиск DNS является синхронным, и я думаю, возможно, и разрешение прокси. После этого все асинхронно. Итак, для сценариев большинства DNS быстрый (обычно кэшированный), и нет прокси-сервера, поэтому он работает асинхронно. К сожалению, достаточно сценариев (особенно из корпоративных сетей), где синхронные операции могут вызвать значительное отставание.

Итак, когда команда писал HttpClient, у них было три варианта:

  1. Fix HttpWebRequest (и друзей), позволяющий полностью асинхронных операций. К сожалению, это сломало бы довольно много кода. Из-за того, как наследование используется в качестве точек расширения в этих объектах, добавление асинхронных методов было бы несовместимым назад.
  2. Напишите свой собственный HttpWebRequest эквивалент. К сожалению, это займет лот работы, и они потеряют всю совместимость с существующим WebRequest-связанным кодом.
  3. Очередь запрашивает пул потоков, чтобы избежать наихудшего сценария (блокирование синхронного кода в потоке пользовательского интерфейса). К сожалению, у этого есть побочные эффекты снижения масштабируемости на ASP.NET, зависящие от потока пула потоков нитей, а также затраты на наихудший сценарий даже для наилучших сценариев.

В идеального мира (то есть, когда мы имеем бесконечный проявитель и время тестера), я бы предпочел (2), но я понимаю, почему они выбрали (3).

На стороне записки, код вы вывесили показывает dangerous use of StartNew, который имеет фактически caused problems из-за его использования TaskScheduler.Current. Это has been fixed в .NET Core - не уверен, когда исправление вернется в .NET Framework.

+0

Благодарим вас за информацию, Стивен. Каждый раз, когда я думаю, что я понимаю свойство 'async/await', здесь вы приходите, и я понимаю, что ничего не знаю. – VMAtm

0

Нет, ваши предположения ошибочны.

  1. StartNew isn't equal to the Run method.
  2. Этот код из HttpClientHandler, а не HttpClient, и вы не изучили this.startRequest код из этого класса. Код, который вы проверяете, представляет собой метод подготовки, который запускает задачу в новом пуле потоков и внутри фактического кода вызова, чтобы запустить HTTP-запрос.
  3. HTTP-соединение создается не на уровне абстракции .NET, и я уверен, что внутри startRequest вы нашли P/Invoke метод, который будет делать реальную работу для:

    • DNS поиска
    • соединение Разъем
    • Отправка запроса
    • ждет ответа
    • и т.д.
  4. Как вы можете видеть, все вышеперечисленное является логикой, которая действительно должна быть вызвана асинхронным способом, поскольку она находится вне рамок .NET, и некоторая операция может занять много времени. Это точно логика, которую следует назвать асинхронно, и во время ожидания этого потока .NET выпускается в ThreadPool для обработки других задач.
Смежные вопросы