Coroutine vs Continuation vs Generator

时间:2009-04-03 21:19:20

标签: generator continuations coroutine

协程与续集和生成器之间有什么区别?

3 个答案:

答案 0 :(得分:116)

我将从发电机开始,因为它们是最简单的情况。正如@zvolkov所提到的,它们是可以在不返回的情况下重复调用的函数/对象,但是当被调用时将返回(yield)一个值然后暂停它们的执行。当他们再次被召唤时,他们将从他们最后暂停执行的地方开始,并再次做他们的事情。

发电机本质上是一种减少(不对称)的协程。协程和生成器之间的区别在于协程可以在最初调用后接受参数,而生成器则不能。

想出一个关于你使用协同程序的简单例子有点困难,但这是我最好的尝试。以此(编写)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

使用协同程序的示例是词法分析器和解析器。如果没有语言中的协程或以某种方式模拟,则需要将lexing和解析代码混合在一起,即使它们实际上是两个独立的问题。但是使用协程,你可以分离出lexing和解析代码。

(我将刷过对称和非对称协程之间的区别。只需说它们是等价的,你可以从一个转换到另一个,不对称协程 - 它们最像发电机 - - 更容易理解。我在概述如何在Python中实现非对称协程。)

延续实际上是非常简单的野兽。它们都是代表程序中另一个点的函数,如果你调用它,将导致执行自动切换到函数所代表的点。你每天都使用非常受限制的版本,甚至没有意识到。例如,例外可以被认为是一种由内而外的延续。我将给你一个基于Python的伪代码延续的例子。

假设Python有一个名为callcc()的函数,这个函数有两个参数,第一个是函数,第二个是调用它的参数列表。对该函数的唯一限制是它所采用的最后一个参数将是一个函数(这将是我们当前的延续)。

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

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

会发生callcc()反过来使用当前延续(foo())调用cc,即对程序中{{1}点的引用}} 被称为。当callcc()调用当前的continuation时,它基本上与告诉foo()返回您正在调用当前continuation的值一样,并且当它执行此操作时,它将堆栈回滚到当前延续已创建,即当您调用callcc()时。

所有这一切的结果将是我们假设的Python变体将打印callcc()

我希望有所帮助,我相信我的解释可以在很短的时间内得到改善!

答案 1 :(得分:32)

Coroutine是几个程序中的一个,它们轮流完成工作,然后停下来控制组中的其他协同程序。

Continuation是一个“指向函数的指针”,你传递给某个程序,当该程序完成时执行(“继续”)。

Generator(在.NET中)是一种语言结构,它可以吐出一个值,“暂停”执行该方法,然后在被要求提供下一个值时从同一点继续。

答案 2 :(得分:8)

在较新版本的Python中,您可以使用generator.send()向Generators发送值,这使得python Generators可以有效地进行协同处理。

python Generator和其他生成器之间的主要区别就是greenlet,在python中,你的yield value只能返回给调用者。在greenlet中,target.switch(value)可以将您带到特定的目标协程并产生target将继续运行的值。