Как я понимаю ключевое слово yield
, если оно используется внутри блока итератора, оно возвращает поток управления вызывающему коду, и когда итератор вызывается снова, он выбирает, где он остановился.
Кроме того, await
не только ждет вызываемого абонента, но и возвращает управление вызывающему абоненту, только чтобы выбрать, где он остановился, когда вызывающий awaits
метод.
Другими словами - нет нити, а "concurrency" async и ждет - иллюзия, вызванная умным потоком управления, детали которого скрыты синтаксисом.
Теперь я бывший программист по сборке, и я очень хорошо знаком с указателями инструкций, стеками и т.д., и я понимаю, как работают обычные потоки управления (подпрограммы, рекурсии, петли, ветки). Но эти новые конструкции - я их не получаю.
Когда достигается await
, как среда выполнения знает, какой фрагмент кода должен выполнить следующий? Как он узнает, когда он может возобновиться там, где он остановился, и как он помнит, где? Что происходит с текущим стеком вызовов, он каким-то образом сохраняется? Что делать, если вызывающий метод делает другие вызовы методов перед ним await
s - почему стек не перезаписывается? И как будет работать среда выполнения во всем этом случае в случае исключения и стека?
Когда достигнуто yield
, как среда выполнения отслеживает точку, в которой вещи должны быть подняты? Как сохраняется состояние итератора?