Основным техническим отличием является то, хотите ли вы иметь возможность уступать из вложенного колла. Это невозможно сделать с помощью сопрограмм без стеков.
Еще одна вещь, которую следует учитывать, состоит в том, что стековые сопрограммы имеют свой собственный стек и контекст (например, маски сигналов, указатель стека, регистры ЦП и т. Д.), Поэтому они занимают больший объем памяти, чем сопрограммы без стеков. Это может быть проблемой, особенно если у вас ограниченная система ресурсов или одновременно существует огромное количество сопрограмм.
Я понятия не имею, как они сравнивают с точки зрения производительности в реальном мире, но в целом сопрограммы без стеков более эффективны, поскольку у них меньше накладных расходов (переключатели задач без стеков не должны обмениваться стеками, хранить / загружать регистры и восстановить маску сигнала и т. д.).
Пример минимальной реализации сопрограммы без стеков см. В сопрограммах Саймона Тэтэма с использованием устройства Даффа . Довольно интуитивно понятно, что они настолько эффективны, насколько это возможно.
Кроме того, на этот вопрос есть хорошие ответы, в которых более подробно рассказывается о различиях между стопками и сопрограммами без стеков.
Как выйти из вложенного вызова в сопрограмм без стеков? & emsp;
Несмотря на то, что я сказал, что это невозможно, это не было на 100% верно: вы можете использовать (по крайней мере два) трюка для достижения этой цели, каждый из которых имеет свои недостатки:
Во-первых, вы должны преобразовать каждый вызов, который должен превратить вашу вызывающую сопрограмму, в сопрограмму. Теперь есть два способа:
Подход на батуте : Вы просто вызываете дочернюю сопрограмму из родительской сопрограммы в цикле, пока она не вернется. Каждый раз, когда вы уведомляете детскую сопрограмму, если она не заканчивается, вы также выдаете вызывающую сопрограмму. Обратите внимание, что этот подход запрещает вызывать дочернюю сопрограмму напрямую, вы всегда должны вызывать внешнюю сопрограмму, которая затем должна повторно вводить весь стек вызовов. Это имеет сложность вызова и возврата O (n) для глубины вложения n . Если вы ожидаете событие, событие должно просто уведомить внешнюю сопрограмму.
Подход родительской ссылки : Вы передаете адрес родительской сопрограммы дочерней сопрограмме, выдает родительскую сопрограмму, и дочерняя сопрограмма вручную возобновляет родительскую сопрограмму после ее завершения. Обратите внимание, что этот подход запрещает прямой вызов любой сопрограммы, кроме самой внутренней. Этот подход имеет сложность вызова и возврата O (1) , поэтому он, как правило, предпочтительнее. Недостатком является то, что вам нужно вручную зарегистрировать самую внутреннюю сопрограмму где-нибудь, чтобы следующее событие, которое хочет возобновить внешнюю сопрограмму, узнало, на какую внутреннюю сопрограмму направить непосредственную цель.
Примечание : под сложность вызова и возврата Я имею в виду количество шагов, предпринятых при уведомлении сопрограммы о ее возобновлении, и шагов, предпринятых после уведомления о возврате вызывающему уведомителю еще раз.