协程、续延和生成器有何不同?
协程、续延和生成器有何不同?
我将从生成器开始讲起,因为它们是最简单的情况。正如 @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
协程常用于词法分析器和解析器中。如果编程语言中没有协程或者没有模拟协程的机制,那么词法分析和解析代码需要混在一起,尽管它们实际上是两个不同的关注点。但使用协程,你可以将词法分析和解析代码分离出来。def foo(x, y, cc):
cc(max(x, y))
biggest = callcc(foo, [23, 42])
print biggest
callcc()
会使用当前的延续(cc
,也就是程序中调用 callcc()
的位置)调用 foo()
。当 foo()
调用当前的延续时,实际上相当于告诉 callcc()
使用你当前调用当前延续的值返回,并且回滚栈到创建当前延续的位置,也就是调用 callcc()
的位置。
最终结果是,我们假设的 Python 变量将打印出 '42'
。
Coroutine是几个过程之一,它们轮流执行任务,然后暂停以将控制权交给组中的其他协程。
Continuation是一个“指向函数”的指针,您可以将其传递给某些过程,在该过程完成时执行(“继续”)。
Generator(在.NET中)是一种语言构造,可以输出一个值,"暂停"方法的执行,然后在请求下一个值时从同一点继续。
generator.send()
向生成器发送值,这使得Python生成器有效地成为协程。yield value
只能返回给调用者。而在Greenlet中,target.switch(value)
可以将您带到特定的目标协程并产生一个值,其中target
将继续运行。yield
调用必须在同一个函数中,该函数称为“生成器”。您无法从子函数中yield
,这就是为什么Python被称为半协程,而Lua具有不对称协程的原因。(虽然有关于传播yield的提案,但我认为那只会让事情更加混乱。) - cdunn2001