协程与延续和发电机有什么区别?
我将从发电机开始,因为它们是最简单的情况.正如@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()
当前的continuation(cc
),即对程序中callcc()
被调用的点的引用.当foo()
调用当前的continuation时,它基本上与告诉callcc()
你使用你正在调用当前continuation的值返回相同,当它这样做时,它会将堆栈回滚到创建当前continuation的位置,即,当你调用时callcc()
.
所有这一切的结果将是我们假设的Python变体将打印出来'42'
.
我希望有所帮助,我相信我的解释可以在很多方面得到改善!
协同程序是几个程序中的一个,它们轮流完成工作,然后停下来控制组中的其他协同程序.
继续是一个"指向函数的指针",你传递给某个程序,当该程序完成时执行("继续").
Generator(在.NET中)是一种语言结构,可以吐出一个值,"暂停"执行该方法,然后在被要求提供下一个值时从同一点继续.
在较新版本的Python中,您可以向Generators with发送值generator.send()
,这使得python Generators可以有效地进行协同处理.
python Generator和其他生成器之间的主要区别就是greenlet,就是在python中,你yield value
只能返回给调用者.在greenlet中,target.switch(value)
可以将您带到特定目标协程并产生一个值target
继续运行的值.