协程与延续和生成器有什么区别?
协程与延续和生成器有什么区别?
Answers:
我将从生成器开始,因为它们是最简单的情况。正如@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'
。
希望能对您有所帮助,并且我肯定我的解释会有所改善!
协程是轮流完成工作然后暂停以控制组中其他协程的几种程序之一。
延续是您传递给某个过程的“函数的指针”,该过程完成后将被执行(“继续”)。
生成器(在.NET中)是一种语言构造,可以吐出一个值,“暂停”该方法的执行,然后在询问下一个值时从同一点进行处理。
在新版本的Python中,您可以使用 generator.send()
,这使python Generators有效地协程。
python生成器与其他生成器(例如greenlet)之间的主要区别在于,在python中,您yield value
只能返回到调用者。处于greenlet时,target.switch(value)
可以将您带到特定的目标协程,并在target
可以继续运行的地方产生一个值。
yield
调用都必须在同一个函数中,该函数称为“生成器”。您不能yield
从子函数中来,这就是为什么Python称为半协程,而Lua具有不对称协程的原因。(有提议提高单产,但我认为这些只是使水