155

coroutine 和 continuation 和 generator 有什么区别?

4

3 回答 3

133

我将从生成器开始,因为它们是最简单的情况。正如@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 变体将 print '42'

我希望这会有所帮助,我相信我的解释可以改进很多!

于 2009-04-03T22:05:22.870 回答
34

协程是轮流完成工作然后暂停以将控制权交给组中的其他协程的几个程序之一。

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

生成器(在 .NET 中)是一种语言构造,它可以吐出一个值,“暂停”方法的执行,然后在被要求输入下一个值时从同一点继续。

于 2009-04-03T21:29:25.453 回答
10

在较新版本的 Python 中,您可以使用 向生成器发送值generator.send(),这使得 python 生成器有效地协同程序。

The main difference between python Generator, and other generator, say greenlet, is that in python, your yield value can only return back to the caller. While in greenlet, target.switch(value) can take you to a specific target coroutine and yield a value where the target would continue to run.

于 2011-08-31T02:51:31.927 回答