Хороший вопрос.
Стек является овеществлением Продолжение. Продолжение - это просто информация о том, что программа собирается делать дальше. В традиционной неасинхронной среде это представляется как обратный адрес в стеке; когда метод возвращает его, он смотрит на стек и ветвится на обратный адрес. Стек также содержит информацию о том, что значения локальных переменных находятся в точке, где продолжается восхождение.
В асинхронной ситуации вся эта информация хранится в куче. Задача содержит делегат, который вызывается, когда задача завершена. Делегат связан с экземпляром класса «закрытия», который содержит поля для любых локальных переменных или другого состояния. И, конечно же, задачи сами являются объектами кучи.
Вы можете спросить: если это так, что продолжение является делегатом, который вызывается после завершения задачи, как то код, который завершает задачу не в стеке вызовов в точке, где завершенности казнят? Задача может выбрать вызов делегата продолжения на , проводя сообщение Windows, и когда цикл сообщения обрабатывает сообщение, он выполняет вызов. Таким образом, вызов затем находится на «вершине» стека, где обычно сидит контур сообщения. (Точные детали стратегии вызова, используемые для продолжения, зависят от контекста, в котором создается задача, см. Более подробное руководство по параллельной библиотеке задач для деталей.)
Хорошая вступительная статья о том, как это все работы можно найти здесь:
https://msdn.microsoft.com/en-us/magazine/hh456403.aspx
некоторые детали были изменены с момента Мадс писал, что статья, но идеи звук. (Ответ i3arnon иллюстрирует, как это произошло, в статье Mads все идет в кучу, но в некоторых сценариях получается избыточный мусор. Более сложный codegen позволяет нам хранить некоторую информацию в стеке. Понимание этого различия не необходимо, чтобы увидеть, как логически представлены продолжения.)
Это развлекательное и просветительское упражнение, чтобы взять вашу программу и на самом деле вытащить всех созданных делегатов и задач, а также то, что ссылки между ними. Дать ему шанс!
@ i3arnon: hah, на моем мониторе почти невозможно сказать разницу между rn и m в этом шрифте! Я немного смутился твоей редакцией. :-) –
Это проблематичное имя. Раньше я писал его с капиталом I (т. Е. I3arnon, так что это выглядело бы как Barnon), но люди ошибочно принимали его за L. – i3arnon
@ i3arnon: мне напомнили глупую головоломку, которую я хотел бы спросить в конце переговоров C#: что это '5432l + 12345'? Это не '66666', как вы думаете. Если вы получите шрифт справа, вы не можете сказать, что это длинный литерал. –