Coroutine vs Continuation vs Generator

В чем разница между сопрограммой и продолжением и генератором?

Ответ 1

Я начну с генераторов, видя, что это самый простой случай. Как отметил @zvolkov, это функции/объекты, которые могут быть повторно вызваны без возврата, но когда вызываемый возвратит (выдает) значение и затем приостановит их выполнение. Когда они снова будут вызваны, они начнут с того места, где они в последний раз приостановили исполнение, и снова сделают свое дело.

Генератор по существу является сокращенным (асимметричным) сопрограммой. Разница между сопрограммой и генератором заключается в том, что сопрограмма может принимать аргументы после ее первоначального вызова, тогда как генератор не может.

Это немного сложно для некоторых с тривиальным примером того, где вы будете использовать сопрограммы, но здесь моя лучшая попытка. Возьмите этот (составленный) код Python в качестве примера.

def my_coroutine_body(*args):
    while True:
        # Do some funky stuff
        *args = yield value_im_returning
        # Do some more funky stuff

my_coro = make_coroutine(my_coroutine_body)

x = 0
while True:
   # The coroutine does some funky stuff to x, and returns a new value.
   x = my_coro(x)
   print x

Примером использования сопрограммы являются лексеры и парсеры. Без сопроводительных текстов на языке или эмулированных каким-то образом, лексинг и синтаксический код необходимо смешивать вместе, хотя они действительно две отдельные проблемы. Но используя сопрограмму, вы можете разделить код лексинга и синтаксического анализа.

(Я собираюсь раскрыть разницу между симметричными и асимметричными сопрограммами. Достаточно сказать, что они эквивалентны, вы можете конвертировать из одного в другое, а асимметричные сопрограммы - наиболее похожие на генераторы - - легче понять. Я рассказал, как можно реализовать асимметричные сопрограммы в Python.)

Продолжения на самом деле довольно простые животные. Все они являются функциями, представляющими другую точку в программе, которая, если вы ее вызываете, заставит выполнение автоматически переключиться на точку, представляемую функцией. Вы используете их очень ограниченные версии каждый день, даже не осознавая этого. Исключения, например, можно рассматривать как своеобразное продолжение изнутри. Я дам вам пример псевдокода на основе Python продолжения.

Скажем, у Python была функция с именем callcc(), и эта функция приняла два аргумента, первая из которых была функцией, а вторая - списком аргументов для ее вызова. Единственным ограничением на эту функцию было бы то, что последний аргумент, который он принимает, будет функцией (которая будет нашим текущим продолжением).

def foo(x, y, cc):
   cc(max(x, y))

biggest = callcc(foo, [23, 42])
print biggest

Что произойдет, так это то, что callcc() в свою очередь вызовет foo() с текущим продолжением (cc), то есть ссылкой на точку в программе, в которой был вызван callcc(). Когда foo() вызывает текущее продолжение, оно по существу совпадает с сообщением callcc() для возврата со значением, которое вы вызываете в текущем продолжении, и когда оно это делает, оно откатывает стек туда, где было создано текущее продолжение, т.е. при вызове callcc().

Результатом всего этого будет то, что наш гипотетический вариант Python напечатает '42'.

Надеюсь, что это поможет, и я уверен, что мои объяснения могут быть улучшены совсем немного!

Ответ 2

Coroutine - одна из нескольких процедур, которые по очереди выполняют свою работу, а затем останавливаются, чтобы дать контроль другим сопрограммам в группе.

Продолжение - это "указатель на функцию", который вы передаете какой-либо процедуре, которая будет выполнена ( "продолжение с" ), когда эта процедура будет выполнена.

Генератор (в .NET) - это языковая конструкция, которая может выплевывать значение, "приостанавливать" выполнение метода и затем исходить из той же точки при запросе следующего значения.

Ответ 3

В более новой версии Python вы можете отправлять значения генераторам с generator.send(), что делает генераторы питона эффективно сопрограммированы.

Основное различие между генератором python и другим генератором, например greenlet, заключается в том, что в python ваш yield value может возвращать только вызывающему. Пока в greenlet, target.switch(value) может перейти к определенной целевой сопрограмме и получить значение, в котором будет продолжаться выполнение target.