Coroutine vs Continuation vs Generator

147

Qual é a diferença entre uma corotina e uma continuação e um gerador?

Mehdi Asgari
fonte
2
Eu me pergunto se corotinas e continuações são efetivamente equivalentes. Eu sei que é possível modelar corotinas com continuações, mas é possível modelar continuações com corotinas ou não, porque as continuações são estritamente mais poderosas?
nalply

Respostas:

127

Vou começar com os geradores, pois são o caso mais simples. Como @zvolkov mencionou, são funções / objetos que podem ser chamados repetidamente sem retornar, mas quando chamados retornarão (produzirão) um valor e suspenderão sua execução. Quando eles são chamados novamente, eles iniciam a partir do ponto em que suspenderam a execução e fazem suas ações novamente.

Um gerador é essencialmente uma corotina cortada (assimétrica). A diferença entre uma corotina e um gerador é que uma corotina pode aceitar argumentos depois de ter sido chamada inicialmente, enquanto um gerador não pode.

É um pouco difícil criar um exemplo trivial de onde você usaria corotinas, mas aqui está minha melhor tentativa. Tome esse código Python (composto) como exemplo.

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

Um exemplo de onde as corotinas são usadas é lexers e analisadores. Sem corotinas no idioma ou emuladas de alguma forma, o código lexing e de análise precisa ser misturado, mesmo que sejam realmente duas preocupações separadas. Mas, usando uma corotina, é possível separar o código lexing e de análise.

(Vou abordar a diferença entre corotinas simétricas e assimétricas. Basta dizer que elas são equivalentes, você pode converter de uma para a outra, e as corotinas assimétricas - que são as mais parecidas com geradores - são as Eu estava descrevendo como é possível implementar coroutines assimétricas em Python.)

Continuações são realmente bestas muito simples. São funções representando outro ponto do programa que, se você o chamar, fará com que a execução mude automaticamente para o ponto que a função representa. Você usa versões muito restritas deles todos os dias sem nem perceber. Exceções, por exemplo, podem ser pensadas como uma espécie de continuação de dentro para fora. Vou dar um exemplo de pseudocódigo baseado em Python de uma continuação.

Digamos que o Python tenha uma função chamada callcc(), e essa função tenha dois argumentos, o primeiro sendo uma função e o segundo uma lista de argumentos para chamá-lo. A única restrição a essa função seria que o último argumento necessário será uma função (que será nossa continuação atual).

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

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

O que aconteceria é que callcc(), por sua vez, chamaria foo()a continuação atual ( cc), isto é, uma referência ao ponto no programa em que callcc()foi chamado. Quando foo()chama a continuação atual, é essencialmente o mesmo que dizer callcc()para retornar com o valor com o qual você está chamando a continuação atual e, quando faz isso, reverte a pilha para onde a continuação atual foi criada, ou seja, quando você chamou callcc().

O resultado de tudo isso seria que nossa hipotética variante Python seria impressa '42'.

Espero que ajude, e tenho certeza que minha explicação pode melhorar um pouco!

Keith Gaughan
fonte
6
Um nit: delimitado continuações são funções, mas undelimited continuações não são: okmij.org/ftp/continuations/undelimited.html#delim-vs-undelim
Frank Shearar
2
Este é um bom ponto. Dito isto, nas aplicações mais práticas, quando as pessoas dizem 'continuação', estão falando de continuações parciais / delimitadas. A introdução de vários outros tipos de continuações dificultaria um pouco a explicação.
Keith Gaughan
1
Continuações não são funções, embora possam ser reificadas em funções. "Dito isto, nas aplicações mais práticas, quando as pessoas dizem 'continuação', estão falando de continuações parciais / delimitadas". Você apontaria para esse uso do termo "continuação"? Eu nunca conheci esse uso. Você também deu um exemplo para uma continuação não limitada, usando call / cc. Os operadores para continuações delimitadas geralmente são "redefinidos" e "shift" (eles podem ter outros nomes).
ivancho
3
Vamos começar com o fato de que faz cinco anos desde que escrevi isso. Você está um pouco atrasado para a festa. Em segundo lugar, eu sei que continuações não limitadas não são funções, mas você tenta explicar como elas funcionam sem se referir a elas como tal, além de manter o idioma direto. Do ponto de vista do programador médio, o fato de uma continuação não limitada não retornar apenas a torna uma função única, que não é correta conforme a definição do que é uma função, mas é pelo menos compreensível .
precisa
2
Não estou atrasado para a festa, pois este é o primeiro resultado que recebo no google quando pesquiso "corotina vs gerador". Eu esperava encontrar algumas boas informações sobre suas diferenças. Enfim, eu encontrei em outro lugar. E não sou o primeiro a apontar que sua explicação sobre continuações está errada. O problema é que alguém irá errar e possivelmente ficará confuso mais tarde quando encontrar a mesma palavra usada para algo diferente.
Ivancho
33

A corotina é um dos vários procedimentos que se revezam no trabalho e depois param para dar controle às outras corotinas do grupo.

A continuação é um "ponteiro para uma função" que você passa para algum procedimento, a ser executado ("continuado com") quando esse procedimento é concluído.

Generator (no .NET) é uma construção de linguagem que pode cuspir um valor, "pausar" a execução do método e prosseguir a partir do mesmo ponto quando solicitado pelo próximo valor.

zvolkov
fonte
Sei que a resposta pode não ser precisa, mas nesse nível de pergunta tentei mantê-la simples. Além disso, eu realmente não entendo tudo isso me :)
zvolkov
Um gerador em python é semelhante à versão C #, mas é implementado como uma sintaxe especial para criar uma instância de um objeto iterador, que retorna os valores retornados pela definição de "função" que você fornece.
Benson
2
Uma pequena correção: "... incluindo pilha de chamadas e todas as variáveis, MAS NÃO SEUS VALORES" (ou simplesmente solte "todas as variáveis"). As continuações não preservam os valores, apenas contêm a pilha de chamadas.
nalply
Não, as continuações não são "ponteiras para uma função". Na implementação mais ingênua, ele contém um ponteiro para funcionar e um ambiente mantém as variáveis ​​locais. E ele nunca retorna, a menos que você use algo como call / cc para capturá-lo com um valor de retorno.
NalaGinrut #
9

Na versão mais recente do Python, você pode enviar valores para os Geradores com generator.send(), o que faz com que os Geradores de python efetivamente sejam rotineiros.

A principal diferença entre o python Generator e outro gerador, digamos greenlet, é que, em python, você yield valuesó pode retornar ao chamador. Enquanto estiver no greenlet, target.switch(value)você pode levá-lo a uma corotina de destino específica e gerar um valor em que o valor targetcontinuaria a ser executado.

Yichuan Wang
fonte
3
Mas no Python, todas as yieldchamadas devem estar na mesma função, chamada de "Gerador". Você não pode yieldde uma sub-função, e é por isso que os Python são chamados de semi-corotinas , enquanto Lua possui corotinas assimétricas . (Existem propostas para propagar os rendimentos, mas acho que só esses turvar as águas.)
cdunn2001
7
@ cdunn2001: (comentário de Winston) Python3.3 introduziu a expressão "yield from" que permite que você produza a partir do subgerador.
Linus Caldwell