Python中的协程与Lua中的协程相比如何?



Lua中的协程支持由coroutine表中的函数提供,主要是create, resumeyield。开发人员将这些协程描述为堆栈式的、一流的和非对称的。

协程在Python中也可用,要么使用增强的生成器(和yield from),要么在3.5版中添加asyncawait

Python中的协程与Lua中的协程相比如何?它们也是堆叠的、一流的和不对称的吗?

为什么Python需要这么多的协程结构(async def, async with, async for,异步推导,…),而Lua可以提供它们只有三个内置函数?

简单的答案是它们是不同的语言。是的,Python协程是堆栈式的、一流的和非对称的。请看这个答案:协程vs延续vs生成器

来自Lua文档:

有些人称非对称协同程序为半协同程序(因为它们不是对称的,它们不是真的对称。然而,其他人使用相同的术语半协程来表示受限制的实现的协程,其中协程只能在以下情况下暂停其执行它里面没有任何辅助功能,也就是说,当它没有的时候控制堆栈中的挂起调用。换句话说,只有主体这种半协同程序可以产生。Python中的生成器就是一个例子半协程的这种意义。

与对称和非对称协程的区别不同协程和生成器之间的区别(如Python所示)是深沉的;生成器的功能还不够强大,无法实现我们可以用true来写几个有趣的结构协同程序。Lua提供了真正的非对称协程。那些喜欢对称协程可以在非对称协程之上实现它们Lua的功能。这是一件容易的事。(基本上,每次转账都是这样)

同样,参见Python开发者邮件列表中的讨论:PEP 492: What is real goal?

[Python协程]也是堆栈的,一级的和不对称的吗?

是的,它们是。

Python中的协程与Lua中的协程相比如何?

Python和Lua在协程实现上的区别是:它能挂起调用者吗?

Python协程不能在调用堆栈中传播" suspend事件"。函数只能挂起自己。因此你最终会得到Christopher Kohlhoff所描述的病毒流控制关键字。被调用方必须将自己标注为"async函数",以便调用约定能够识别返回类型。并且调用者必须在每个调用站点(await关键字)的调用堆栈中冗余地重新传播挂起请求。

Bob Nystrom将这种现象描述为双色问题:https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/.

这是一个Lua用户的博客文章,他得到了:https://leafo.net/posts/itchio-and-coroutines.html.

下面是来自Java社区的人:https://www.infoq.com/presentations/continuations-java/.

为什么Python需要这么多的协程结构(async def, async with, async for,异步推导,…),而Lua可以提供它们只有三个内置函数?

Python协程不能挂起调用者,因此它们为每个控制流构造提供了不同的语法糖,以将"挂起事件"从被调用者传播到调用者。Lua不需要这个,因为Lua协程可以直接挂起整个调用栈。

我刚刚第一次看了lua,其中包括sieve.lua的现场演示。它是使用协同程序的埃拉托斯人筛的实现。我的第一个想法是:这在python中看起来会干净得多:

#!/usr/bin/env python3
# sieve.py
# the sieve of Eratosthenes programmed with a generator functions
# typical usage: ./sieve.py 500 | column
import sys
# generate all the numbers from 2 to n
def gen(n):
    for i in range(2,n):
        yield i
# filter the numbers generated by `g', removing multiples of `p'
def filter(p, g):
    for n in g:
        if n%p !=0:
            yield n
N=int(sys.argv[1]) if len(sys.argv)>1 else 500 # from command line
x=gen(N)                     # generate primes up to N
while True:
    try:
        n = next(x)          # pick a number until done
    except StopIteration:
        break
    print(n)                 # must be a prime number
    x = filter(n, x)         # now remove its multiples

这与问题没有多大关系,但是在我使用Python 3.4.3的机器上,N>7500的堆栈溢出发生在某个地方。使用sieve.luaLua 5.2.3,堆栈溢出已经发生在N>530

生成器对象(表示挂起的协程)可以像任何其他对象一样传递,并且内置的next()可以在任何地方应用于它,因此python中的协程是一流的。如果我说错了,请指正。

最新更新