当前位置:  开发笔记 > 编程语言 > 正文

Coroutine vs Continuation vs Generator

如何解决《CoroutinevsContinuationvsGenerator》经验,为你挑选了3个好方法。

协程与延续和发电机有什么区别?



1> Keith Gaugha..:

我将从发电机开始,因为它们是最简单的情况.正如@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'.

我希望有所帮助,我相信我的解释可以在很多方面得到改善!


一个nit:_delimited_ continuations是函数,但是_undelimited_ continuations不是:http://okmij.org/ftp/continuations/undelimited.html#delim-vs-undelim
让我们从我写这篇文章以来已经五年了。你参加聚会有点晚了。其次,我*知道*无限延续不是函数,但是您在尝试解释它们的工作原理时没有提及它们,同时也保持了语言的直接性。从普通程序员的角度来看,无界延续不会返回的事实只会使它成为一次性函数,按照函数的定义,这不是“正确的”,但至少*可以理解*。
那是个很好的观点.也就是说,在大多数实际应用中,当人们说'延续'时,他们谈论的是部分/分隔的延续.引入各种其他类型的延续会使解释变得有些混乱.
我参加聚会不晚,因为这是我搜索“协程与发生器”时在Google中获得的第一个结果。我希望找到一些有关它们之间差异的良好信息。无论如何,我在其他地方找到了它。我不是第一个指出您对延续的解释是错误的人。问题是,某人遇到错误时可能会弄错它,并且当他或他遇到用于不同事物的相同单词时可能会感到困惑。

2> zvolkov..:

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

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

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


一个小的修正:"......包括调用堆栈和所有变量但不是它们的值"(或者只是删除"所有变量").Continuations不保留值,它们只包含调用堆栈.

3> Yichuan Wang..:

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

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


@ cdunn2001 :(由Winston评论)Python3.3引入了"yield from"表达式,让你从子生成器中产生.
但在Python中,所有`yield`调用必须在同一个函数中,称为"生成器".你不能从子函数中"屈服",这就是为什么Python被称为*半协同*,而Lua有*不对称协程*.(有提议来宣传收益率,但我认为那些只会使水域变得混乱.)
推荐阅读
放ch养奶牛
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有