Но я не понимаю, почему вдруг в случае задачи вы можете рассчитывать на другое оборудование вместо вычислений на ЦП, что каким-то образом позволяет не создавать новый поток.
Поскольку ЦП является не только возможным источником параллелизма в наборе аппаратных устройств.
Потоки логически связаны с ЦП, поэтому для любой связанной с ЦП рабочей нагрузки мы используем потоки либо явно, создавая их, либо используя механизмы более высокого уровня, такие как пул потоков или Task.Run
, либо неявно - каждое приложение запускается внутри некоторогопоток по умолчанию в любом случае.
Но есть другой вид операций - операции ввода / вывода, которые подразумевают использование аппаратных устройств, отличных от CPU <-> RAM, таких как диски, сетевые адаптеры, клавиатура, различные периферийные устройства и т. Д. Такие устройства работают с данными.который приходит и выходит асинхронно - никто не знает, когда вы в следующий раз нажмете клавишу или новые данные поступят из сети.Чтобы справиться с асинхронностью, такие аппаратные устройства могут передавать данные без участия ЦП (проще говоря, устройству предоставляется несколько адресов в ОЗУ, где находятся данные, и затем оно может выполнять передачу самостоятельно).Это очень упрощенная картина того, что происходит, но вы можете думать, что на этом большинство асинхронных потоков заканчиваются.Как вы видите, процессор там не требуется, поэтому нет необходимости создавать новый поток.Что касается входящих данных, то механизм очень похож, с той лишь разницей, что, как только данные поступают, они помещаются в определенную область ОЗУ, чтобы быть доступными для дальнейшего использования.Когда устройство завершает переход данных (входящий или исходящий), оно выдает специальный сигнал, называемый прерыванием, чтобы уведомить ЦПУ о завершении операции, и ЦП реагирует на прерывание с помощью запуска выполнения конкретного кода, который обычно находится в драйвере аппаратного устройства - таким образом, драйверМожно отправить уведомление на более высокие уровни.Прерывания могут происходить от устройств асинхронно, и процессор обязан приостановить любое текущее выполнение, которое он выполняет в данный момент, и переключиться на обработчик прерываний.Когда драйвер устройства выполняет обработчик прерывания, он отправляет уведомление о завершении ввода-вывода на более высокие уровни стека ОС, и, наконец, это уведомление попадает в приложение, которое инициировало операцию ввода-вывода.Как это сделать, в основном зависит от ОС, на которой работает приложение.Для Windows существует специальный механизм, называемый Порты завершения ввода-вывода , который подразумевает использование некоторого пула потоков для обработки уведомлений о завершении ввода-вывода.Эти уведомления, наконец, поступают из CLR в приложение и инициируют выполнение продолжений, которые в конечном итоге могут выполняться в отдельном потоке, который является либо потоком из пула потоков ввода-вывода, либо любым другим потоком, в зависимости от конкретной реализации awaiter .
Что касается общей идеи статьи, на которую вы ссылаетесь, то ее можно перефразировать следующим образом: за async/await
нет никакого потока, если вы не создадите его явно, потому что await/async
является только расширенной структурой уведомлений как таковой,который может быть расширен для работы с любым асинхронным механизмом внизу.