为什么我们需要在Python中使用协程?

11

我很久以前就听说过协程,但从未使用过。据我所知,协程与生成器类似。

为什么我们需要在Python中使用协程?


你应该能够通过谷歌找到答案。在这里得到的任何答案可能会含有主观性和冗长性。这就是为什么这类问题被视为SO的离题内容。 - Paul Rooney
我同意。我想要一个能够使用它的实际例子。 - Rainmaker
3
我认为 David Beasley(dabeaz)是Python协程的主要倡导者之一。他的博客或PyCon演讲可能是了解该主题的好起点。 - Paul Rooney
它们是解决问题的另一个有用工具。 - wwii
2个回答

19

生成器使用yield返回值。Python生成器函数也可以通过(yield)语句消耗值。此外,生成器对象上的两个新方法send()close()为消费和生产值的对象创建了一个框架。定义这些对象的生成器函数称为协程

协程使用(yield)语句来消耗值,如下所示:

value = (yield)

使用这个语法,执行会在此语句处暂停,直到调用对象的send方法并传入一个参数:

coroutine.send(data)

然后,执行继续,将值分配给数据的值。为了表示计算的结束,我们使用 close() 方法关闭协程。这会在协程内部引发一个 GeneratorExit 异常,我们可以使用 try/except 语句捕获它。

下面的示例说明了这些概念。这是一个打印与提供的模式匹配的字符串的协程。

def match(pattern):
    print('Looking for ' + pattern)
    try:
        while True:
            s = (yield)
            if pattern in s:
                print(s)
    except GeneratorExit:
        print("=== Done ===")

我们用一个模式进行初始化,并调用 __next__() 来开始执行:

m = match("Jabberwock")
m.__next__()
Looking for Jabberwock

调用__next__()会导致函数体被执行,因此"正在寻找jabberwock"这行代码将被输出。执行将继续直到遇到语句line = (yield)。然后,执行暂停,并等待一个值被发送到m。我们可以使用send()向其发送值。


4
我喜欢你的帖子,但也许它可以详细说明为什么/何时它们比函数或对象更好? - Roelant
如果您在此处使用@coroutine修饰符对函数进行了描述,那么您也可以省略m.next()调用。有关详细信息,请参见https://www.dabeaz.com/coroutines/coroutine.py。 - Marco Fumagalli
你能详细解释一下_next__()吗?我的问题是,为什么Python只有在到达yield时才执行函数呢?是什么触发了这种行为?Python是否正在扫描整个函数并检查它是否看到了“yield”,然后决定match("")不是函数调用,而是一种闭包?我有点困惑。 - lalala
你没有提到协程的使用场景和原因,只是给出了执行它们的步骤。 - Bhanu Tez

4

协程与生成器类似,但有一些区别。主要区别如下:

  1. 生成器是数据生产者
  2. 协程是数据消费者

详情请参考此处


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接