поток может одновременно и заниматься другой работой, и ожиданием завершения таска?
Многие компиляторы разворачивают синтаксический сахар в иные пути выполнения инструкций
Просто есть N потоков-воркеров и есть очередь, из которой эти воркеры разбирают задачи. После await весь дальнейший код кладется на ожидание и кто его подберет, тот и будет дальше обрабатывать
поток уходит в пул. Соответственно его может взять другой поток для решения какой-то задачи. Он решает эту задачу и потом, по завершению таска, (по событию, а не лонг-поллинг какой-нибудь) магически как-то делегирует эту задачу что ли другому потоку, а сам возвращается к тому месту, где был await (если нужно чтобы продолжил исполнение тот же самый поток который был и до await). Если этого не надо, то продолжает исполнять ту самую полезную задачу, а продолжение после await исполняет поток который был внутри той async функции которая была вызвана
Для I/0 или для CPU-bound ? Для CPU-bound: 1) Разворачивает метод после оператора await в детерминированную машину состояний 2) Регистрирует делегат метода в глобальную очередь пула потоков 3) Свободный поток исполняет метод, скорее всего это будет тот же поток, что и регистрировал делегат в очередь, так как это уменьшит вероятность переключения контекста или дорогостоящей операции создании нового потока(виртуальные потоки CLR мапятся на нативные, виртуальные - крайней дешевые, системные - нет) Для I/O: Все тоже самое, что и для Cpu-bound, только: 1) Исполняющий поток передает управление IRP(I/O Request Packet, про файловые дескрипторы и различные сейфхендлеры сами прочитаете) 2) IRP попадает в очередь к драйверу устройства 2) Поток не дожидаясь завершения I/o операции возвращается в пул 3) ICP((I/O Completion Port) после завершения региструет делегат в глобальную очередь пула потоков 4) Свободный поток из пула активизирует делегат и безопасно читает данные, полученные в процессе IRP, готово
Обсуждают сегодня