python中的协程(coroutine)

python中的协程(coroutine)

1.协程与子例程(subcoroutine)的比较

因为相对于子例程,协程可以有多个入口和出口点,可以用协程来实现任何的子例程。事实上,正如Knuth所说:“子例程是协程的特例。”每当子例程被调用时,执行从被调用子例程的起始处开始;然而,接下来的每次协程被调用时,从协程返回(或yield)的位置接着执行。因为子例程只返回一次,要返回多个值就要通过集合的形式。这在有些语言,如Forth里很方便;而其他语言,如C,只允许单一的返回值,所以就需要引用一个集合。相反地,因为协程可以返回多次,返回多个值只需要在后继的协程调用中返回附加的值即可。在后继调用中返回附加值的协程常被称为产生器。

子例程容易实现于堆栈之上,因为子例程将调用的其他子例程作为下级。相反地,协程对等地调用其他协程,最好的实现是用continuations(由有垃圾回收的堆实现)以跟踪控制流程。维基百科-协程

2.协程在Python中的使用

1.使用Generator

def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None)
    i = 0
    for i<5:
        i = i+1
        print('[PRODUCER] Producing %s...' % n)
        c.send(i)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()

c = consumer()
produce(c)

在上面的代码中,首先c.send(None)启动consumer(),执行到了yield处时,comsumer()中断执行,返回到了produce中执行,进入for 循环,通过c.send(i)将i发送给了consumer中yield处,produce在此处中断,在while循环中继续,到yield处又返回到了produce内。
可以通过打印print语句查看运行步骤。

2.使用asyncio模块

先通过pip下载asyncio模块
通过@asyncio.coroutine注释generator成为一个coroutine,在程序中通过yield from 关键字可以调用别的generator,下面就是例子

import threading
import asyncio

@asyncio.coroutine
def hello():
    print('Hello world! (%s)' % threading.currentThread())
    yield from asyncio.sleep(1)
    print('Hello again! (%s)' % threading.currentThread())

loop = asyncio.get_event_loop()
tasks = [hello(), hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

asyncio.sleep()也是一个coroutine,用来模拟io操作当执行,当执行到sleep的时候,直接跳过来执行其他的coroutine,所以打印出来的结果应该是

Hello world! (<_MainThread(MainThread, started 140735195337472)>)
Hello world! (<_MainThread(MainThread, started 140735195337472)>)
(暂停约1秒)
Hello again! (<_MainThread(MainThread, started 140735195337472)>)
Hello again! (<_MainThread(MainThread, started 140735195337472)>)

3.使用async 和await语法

在python3.5之后添加的async和await用来实现协程,用法是将@asyncio.coroutine用async替换,将yield from用await来替换

出自 廖雪峰的Blog

猜你喜欢

转载自blog.csdn.net/u013648164/article/details/73330484