Как DownloadStringTaskAsync и DownloadStringAsync удается не блокировать поток пользовательского интерфейса?

Насколько я знаю, они оба не имеют ключевого слова «асинхронный». Они оба создают новый поток при загрузке? Я слышал, что люди говорят, что они не используют новый поток. Тогда как это делается?

Обычный метод DownloadString действительно блокирует поток пользовательского интерфейса, но как другим двум методам удается это сделать без использования ключевого слова «ожидание» для возврата из метода и ожидания завершения операции.

Из официальной документации : «Ресурс загружается асинхронно с использованием ресурсов потоков, которые автоматически выделяются из пула потоков».

UnholySheep 25.12.2020 01:32

Ух ты. Я этого не видел. У меня была эта проблема из-за того же самого с ConnectAsync TcpClient. в официальной документации нет информации о том, использует ли он поток из пула потоков или нет.

Enlight 25.12.2020 01:36

Настоятельно рекомендую HttpClient, его интерфейс и методы действительно имеют смысл :)

jjxtra 25.12.2020 01:36

DownloadStringTaskAsync предназначен для использования с await. Вы используете его без? Можете ли вы показать нам, как вы его используете?

Theodor Zoulias 25.12.2020 01:37

Я использую его с ожиданием, так как, по-видимому, для загрузки используется новый поток. Однако в официальной документации также указано, что вы не должны использовать новый поток с работой, связанной с вводом-выводом. Загрузка вещей — это операция ввода-вывода, однако DownloadStringTaskAsync действительно использует новый поток для выполнения задачи. Почему это?

Enlight 25.12.2020 01:41

Откуда вы знаете, что DownloadStringTaskAsync использует новый поток для выполнения задачи? АФАИК это не правда. Документация, в которой говорится об «асинхронной загрузке с использованием ресурсов потока», ИМХО вводит в заблуждение. Аппаратное обеспечение, используемое для извлечения данных из Интернета, — это сетевая карта, а не ЦП. И когда мы говорим о потоках, мы говорим о процессоре. Понятие «потоки» неприменимо к сетевым картам, видеокартам или дисковым контроллерам.

Theodor Zoulias 25.12.2020 21:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Насколько я знаю, они оба не имеют ключевого слова «асинхронный». Они оба создают новый поток при загрузке?

Правда, они не используют асинхронность. Но вам не обязательно использовать async, чтобы быть асинхронным.

Они не создают новые потоки, если под этим вы подразумеваете, что они просто ставят в очередь блокирующие работы в пул потоков. Они «используют ресурсы потока» после завершения операции, хотя я бы сказал, что документация вводит в заблуждение.

Я слышал, что люди говорят, что они не используют новый поток. Тогда как это делается?

См. Темы нет. Таким образом, настоящий асинхронный ввод-вывод использует обратные вызовы, которые обычно заканчиваются портом завершения, который в .NET является частью пула потоков. Однако нет ни одного потока, заблокированного при выполнении операций ввода-вывода; скорее, потоки ввода-вывода пула потоков (не рабочие потоки) используются для обслуживания работы порта завершения по мере ее завершения.

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

Enlight 25.12.2020 02:08

Потоки ввода-вывода используются для выполнения задач, да. Но они не используются для загрузки. Они будут использоваться для завершения задачи загрузки после завершения загрузки.

Stephen Cleary 25.12.2020 03:05

Задача загрузки — это то, что затем блокирует поток пользовательского интерфейса. Я изо всех сил пытаюсь понять, как .NET удается делать это без блокировки. Блог, кажется, объясняет это очень ясно, я уверен, но я просто не понимаю многих терминов.

Enlight 25.12.2020 03:14

@Enlight: вы можете думать об этом как об обратных вызовах. Метод Download*Async запросит загрузку и зарегистрирует обратный вызов. Затем он возвращает задачу. Когда загрузка завершается, обратный вызов завершает задачу.

Stephen Cleary 25.12.2020 03:32

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

Enlight 25.12.2020 03:40

@Enlight: это упрощение, но общий смысл таков. Загрузка состоит из двух сетевых сообщений: запроса и ответа. Когда поток отправил запрос, почему он должен ждать, пока не придет ответ? Он может просто отправить запрос и зарегистрировать обратный вызов, чтобы приложение могло обработать ответ, когда он поступит. Нет необходимости в потоке, чтобы просто сидеть и ждать.

Stephen Cleary 25.12.2020 18:32

Верно, да. Теперь это имеет смысл. Что на самом деле не имеет смысла, так это то, как он освобождает поток, а не просто ждет. С асинхронными методами вы можете использовать ключевое слово await для возврата из метода и возврата позже, когда он будет завершен. С DownloadStringAsync у него нет ключевого слова async. Я предполагаю, что это делается другим способом под капотом, используя DownloadStringAsync?

Enlight 25.12.2020 19:02

@Enlight: он использует TaskCompletionSource<T> для создания задачи, которая будет завершена позже.

Stephen Cleary 26.12.2020 03:30

Правильно, насколько я понял, он создает запрос и, возвращая TaskCompletionSource, потоку не нужно ждать, пока он не завершится. Это верно?

Enlight 26.12.2020 23:01

Да; при возврате поток разблокируется.

Stephen Cleary 28.12.2020 16:45

«TaskCompletionSource превращает что-то, что уже является асинхронным, в задачу». При этом использует ли он внутреннее ключевое слово «ожидание» для возврата?

Enlight 28.12.2020 18:39

@Enlight: Нет. Он использует обратные вызовы.

Stephen Cleary 28.12.2020 19:00

Итак, что-то вроде: он запрашивает загрузку, передает обратный вызов, возвращает и после завершения он перезванивает, чтобы завершить операцию.

Enlight 28.12.2020 19:50

@Enlight: Ага.​

Stephen Cleary 28.12.2020 23:55

Другие вопросы по теме