Ответ 1
Во-первых, спасибо, что посмотрели CO2:)
Boost.Coroutine doc описывает преимущество многоуровневой справки:
stackfulness
В отличие от стекированной сопрограммы сложная сопрограмма может быть приостановлена изнутри вложенного стекового кадра. Выполнение возобновляется при точно такую же точку в коде, где она была приостановлена раньше. С стекированная сопрограмма, только приостановка верхнего уровня может быть приостановлена. Любая процедура, вызванная этой программой верхнего уровня, не может сама приостанавливаться. Это запрещает предоставление приостанавливать/возобновлять операции в подпрограммах внутри библиотека общего назначения.
первоклассное продолжение
Можно продолжить первоклассное продолжение как аргумент, возвращаемый функцией и сохраняемый в структуре данных, для будет использоваться позже. В некоторых реализациях (например, С# yield) продолжение невозможно напрямую получить или напрямую манипулировать.
Без стеричности и первоклассной семантики, некоторые полезные действия потоки управления не могут поддерживаться (например, совлокальные многозадачность или контрольная точка).
Что это значит для вас? например, представьте, что у вас есть функция, которая принимает посетителя:
template<class Visitor>
void f(Visitor& v);
Вы хотите преобразовать его в итератор, со стеквой сопрограммой, вы можете:
asymmetric_coroutine<T>::pull_type pull_from([](asymmetric_coroutine<T>::push_type& yield)
{
f(yield);
});
Но с помощью стекированной сопрограммы нет возможности сделать это:
generator<T> pull_from()
{
// yield can only be used here, cannot pass to f
f(???);
}
В общем, stackful coroutine является более мощным, чем stackless coroutine. Итак, почему мы хотим, чтобы безшовная сопрограмма? короткий ответ: эффективность.
В стеке coroutine обычно требуется выделить определенный объем памяти, чтобы разместить его стек времени выполнения (должен быть достаточно большим), а контекстный переключатель более дорогой по сравнению с безплатным, например. Boost.Coroutine занимает 40 циклов, в то время как CO2 занимает всего 7 циклов в среднем на моей машине, потому что единственное, что требуется восстановить для стекирования сопрограммы, - это счетчик программ.
Тем не менее, с поддержкой языка, вероятно, стековый сопроцессор может также воспользоваться преимуществом вычисляемого максимальным размером компилятора для стека, пока в сопрограмме нет рекурсии, поэтому использование памяти также может быть улучшено.
Говоря о стекированной сопрограмме, помните, что это не означает, что нет стека времени выполнения вообще, это означает только то, что он использует тот же самый пакет времени выполнения, что и сторона хоста, поэтому вы можете также вызывать рекурсивные функции, просто, чтобы все рекурсии произошли в стеке времени выполнения хоста. Напротив, с помощью stackful coroutine, когда вы вызываете рекурсивные функции, рекурсии будут выполняться в собственном стеке coroutine.
Чтобы ответить на вопросы:
- Существуют ли какие-либо ограничения на использование переменных автоматического хранения (т.е. переменные "в стеке" )?
Нет. Это ограничение эмуляции CO2. При поддержке языка переменные автоматического хранения, видимые для сопрограммы, будут размещены на внутренней памяти сопрограммы. Обратите внимание, что мой акцент на "видимый на сопрограмме", если сопроцессор вызывает функцию, которая использует внутренние переменные хранилища внутри, то эти переменные будут помещены в стек выполнения. Более конкретно, stackless coroutine должен сохранять только переменные/временные файлы, которые могут быть использованы после возобновления.
Чтобы быть ясным, вы также можете использовать автоматические переменные хранилища в корпусе CO2 coroutine:
auto f() CO2_RET(co2::task<>, ())
{
int a = 1; // not ok
CO2_AWAIT(co2::suspend_always{});
{
int b = 2; // ok
doSomething(b);
}
CO2_AWAIT(co2::suspend_always{});
int c = 3; // ok
doSomething(c);
} CO2_END
Пока определение не предшествует await
.
- Существуют ли какие-либо ограничения на то, какие функции я могу вызвать из непрозрачная сопрограмма?
Нет.
- Если нет сохранения контекста стека для непрозрачной сопрограммы, где происходят переменные автоматического хранения, когда сопрограмма работает?
В ответ на это, стекированная сопрограмма не заботится о переменных автоматического хранения, используемых в вызываемых функциях, они просто будут помещены в стандартный стек времени выполнения.
Если у вас есть какие-либо сомнения, просто проверьте исходный код CO2, это поможет вам понять механику под капотом;)