Python 中的协程和 Lua 中的协程有什么区别?

在 Lua 中,协程通过 coroutine 表中的函数(主要是 createresumeyield)来支持。开发者将这些协程描述为堆栈式、一等公民和不对称的 (参考链接)

Python 中也有协程,可以使用增强的生成器(和 yield from)或者在 3.5 版本中新增的 asyncawait 来实现 (参考链接)

Python 中的协程和 Lua 中的协程有什么区别?它们是否也是堆栈式、一等公民和不对称的?

为什么 Python 要使用这么多构造(async defasync withasync for异步推导式(参考链接)等等)来实现协程,而 Lua 只需要三个内置函数就可以提供呢?

点赞
用户1700939
用户1700939

我刚刚看了一下 lua,其中包括了 sieve.lua 实时演示。它是使用协程实现 Erathostenes 筛选器的一种实现。我立即想到的是:在 Python 中,这看起来会更加简洁:

#!/usr/bin/env python3

# sieve.py
# 使用生成器函数编写的 Eratosthenes 筛选器
# 典型用法: ./sieve.py 500 | column

import sys

# 从 2 到 n 生成所有数字
def gen(n):
    for i in range(2,n):
        yield i

# 过滤 `g` 生成的数字,删除 `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 # 从命令行输入
x=gen(N)                     # 生成素数,最大为 N
while True:
    try:
        n = next(x)          # 每次选取一个数字,直到完成
    except StopIteration:
        break
    print(n)                 # 必须是质数
    x = filter(n, x)         # 现在删除它的倍数

这与问题无关,但在我的机器上,使用 Python 3.4.3,当 N>7500 时会发生堆栈溢出。使用 Lua 5.2.3sieve.lua,堆栈溢出在 N>530 的情况下就已经发生了。

生成器对象(代表一个挂起的协程)可以像任何其他对象一样传递,而 next() 函数可以在任何地方应用于它,因此,Python 中的协程是一等公民。如果我错了,请纠正我。

2016-09-30 09:22:58
用户584846
用户584846

简单的答案是它们是不同的语言。是的,Python 协程是堆栈系统、一等和非对称的。详见此回答:Coroutine vs Continuation vs Generator

来自 Lua 文档

有些人称非对称协程为半协程(semi-coroutines)(因为它们不是对称的,它们不是真正的 co)。然而,其他人使用相同的术语“半协程”来表示协程的限制实现,其中协程只能在不在任何辅助函数中时暂停其执行,也就是说,当在其控制堆栈中没有挂起的调用时。换句话说,只有这种半协程的主体部分可以 yield。Python 中的生成器就是此意义上半协程的例子。

与对称和非对称协程之间的区别不同,协程和生成器之间的区别(如 Python 中所示)是深层次的;生成器不足以实现我们可以使用真正协程编写的多个有趣的构造。Lua 提供了真正的、非对称的协程。那些喜欢对称协程的人可以在 Lua 的非对称设施之上实现它们。这是一项简单的任务。(基本上,每个转移都执行 yield,然后再执行 resume。)

还请参见 Python 的开发者邮件列表中此讨论:PEP 492: What is the real goal?

2016-10-05 17:07:32