Насколько я знаю, они оба не имеют ключевого слова «асинхронный». Они оба создают новый поток при загрузке? Я слышал, что люди говорят, что они не используют новый поток. Тогда как это делается?
Обычный метод DownloadString действительно блокирует поток пользовательского интерфейса, но как другим двум методам удается это сделать без использования ключевого слова «ожидание» для возврата из метода и ожидания завершения операции.
Ух ты. Я этого не видел. У меня была эта проблема из-за того же самого с ConnectAsync TcpClient. в официальной документации нет информации о том, использует ли он поток из пула потоков или нет.
Настоятельно рекомендую HttpClient, его интерфейс и методы действительно имеют смысл :)
DownloadStringTaskAsync
предназначен для использования с await
. Вы используете его без? Можете ли вы показать нам, как вы его используете?
Я использую его с ожиданием, так как, по-видимому, для загрузки используется новый поток. Однако в официальной документации также указано, что вы не должны использовать новый поток с работой, связанной с вводом-выводом. Загрузка вещей — это операция ввода-вывода, однако DownloadStringTaskAsync действительно использует новый поток для выполнения задачи. Почему это?
Откуда вы знаете, что DownloadStringTaskAsync
использует новый поток для выполнения задачи? АФАИК это не правда. Документация, в которой говорится об «асинхронной загрузке с использованием ресурсов потока», ИМХО вводит в заблуждение. Аппаратное обеспечение, используемое для извлечения данных из Интернета, — это сетевая карта, а не ЦП. И когда мы говорим о потоках, мы говорим о процессоре. Понятие «потоки» неприменимо к сетевым картам, видеокартам или дисковым контроллерам.
Насколько я знаю, они оба не имеют ключевого слова «асинхронный». Они оба создают новый поток при загрузке?
Правда, они не используют асинхронность. Но вам не обязательно использовать async
, чтобы быть асинхронным.
Они не создают новые потоки, если под этим вы подразумеваете, что они просто ставят в очередь блокирующие работы в пул потоков. Они «используют ресурсы потока» после завершения операции, хотя я бы сказал, что документация вводит в заблуждение.
Я слышал, что люди говорят, что они не используют новый поток. Тогда как это делается?
См. Темы нет. Таким образом, настоящий асинхронный ввод-вывод использует обратные вызовы, которые обычно заканчиваются портом завершения, который в .NET является частью пула потоков. Однако нет ни одного потока, заблокированного при выполнении операций ввода-вывода; скорее, потоки ввода-вывода пула потоков (не рабочие потоки) используются для обслуживания работы порта завершения по мере ее завершения.
В блоге много терминов, которые я, кажется, не очень ясно понимаю. Насколько я понял, потоки ввода-вывода используются не пользователем, а фреймворком для выполнения задач (в нашем случае я предполагаю, что он использует потоки ввода-вывода для загрузки), и в этом разница между Worker и Потоки ввода-вывода.
Потоки ввода-вывода используются для выполнения задач, да. Но они не используются для загрузки. Они будут использоваться для завершения задачи загрузки после завершения загрузки.
Задача загрузки — это то, что затем блокирует поток пользовательского интерфейса. Я изо всех сил пытаюсь понять, как .NET удается делать это без блокировки. Блог, кажется, объясняет это очень ясно, я уверен, но я просто не понимаю многих терминов.
@Enlight: вы можете думать об этом как об обратных вызовах. Метод Download*Async
запросит загрузку и зарегистрирует обратный вызов. Затем он возвращает задачу. Когда загрузка завершается, обратный вызов завершает задачу.
Не могли бы вы показать визуализацию примера, который вы только что сделали? Насколько я понял, если он запрашивает загрузку, кто его загружает? если тот же поток загрузит его, не будет ли он заблокирован?
@Enlight: это упрощение, но общий смысл таков. Загрузка состоит из двух сетевых сообщений: запроса и ответа. Когда поток отправил запрос, почему он должен ждать, пока не придет ответ? Он может просто отправить запрос и зарегистрировать обратный вызов, чтобы приложение могло обработать ответ, когда он поступит. Нет необходимости в потоке, чтобы просто сидеть и ждать.
Верно, да. Теперь это имеет смысл. Что на самом деле не имеет смысла, так это то, как он освобождает поток, а не просто ждет. С асинхронными методами вы можете использовать ключевое слово await для возврата из метода и возврата позже, когда он будет завершен. С DownloadStringAsync у него нет ключевого слова async. Я предполагаю, что это делается другим способом под капотом, используя DownloadStringAsync?
@Enlight: он использует TaskCompletionSource<T>
для создания задачи, которая будет завершена позже.
Правильно, насколько я понял, он создает запрос и, возвращая TaskCompletionSource, потоку не нужно ждать, пока он не завершится. Это верно?
Да; при возврате поток разблокируется.
«TaskCompletionSource превращает что-то, что уже является асинхронным, в задачу». При этом использует ли он внутреннее ключевое слово «ожидание» для возврата?
@Enlight: Нет. Он использует обратные вызовы.
Итак, что-то вроде: он запрашивает загрузку, передает обратный вызов, возвращает и после завершения он перезванивает, чтобы завершить операцию.
@Enlight: Ага.
Из официальной документации : «Ресурс загружается асинхронно с использованием ресурсов потоков, которые автоматически выделяются из пула потоков».