Python之协程(coroutine)

Python之协程(coroutine)

标签(空格分隔): Python进阶


coroutine和generator的区别

generator是数据的产生者。即它pull data 通过 iteration
coroutine是数据的消费者。它push data into pipeline 通过 send

generator的通常用法

generator的作用是可以作为data pipeline使用.
例如可以使用coroutine来做filter,
或者多路的broadcast。

generator通常是yield和for的运用。
示例代码1:

def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a+b
        
for i in fib():
    print(i)
    

用yield接收data,通过for循环将每一步data输出。

下面介绍coroutine, 它的yield接收外部value,而不是保存内部value。

def grep(pattern):
    print("Searching for", pattern)
    while True:
        line = (yield)
        if pattern in line:
            print line
            

此处的 yield并不包含任何value,它接受外部.send()方法传过来的value.

search = grep('coroutine')
next(search)
# Output: Searching for coroutine
search.send("I love you")
search.send("Don't you love me?")
search.send("I love coroutines instead!")
# Output: I love coroutines instead!

search.close()

先通过next(),start这个coroutine.
之后每一次调用send(),将参数通过yield传入line中。同时相当于自动运行.next()到下一个value. 最终调用.close()关闭这个协程。

示例1:作为filter使用

import time
def follow(thefile, target):
    thefile.seek(0,2) # Go to the end of the file
    while True:
        line = thefile.readline()
        if not line:
            time.sleep(0.1) # Sleep briefly
            continue
        target.send(line)
 
  @coroutine
def printer():
 while True:
    line = (yield)
    print line
    
@coroutine
def grep(pattern,target):
    while True:
        line = (yield) # Receive a line
        if pattern in line:
            target.send(line) # Send to next stage
            
f = open("access-log")
follow(f,grep('python',printer()))            

dataflow如下:###

follow将file中的每一行读取,send到coroutine中,grep查找匹配的line,send到下一个coroutine中,printer接收send过来的data,并且输出。 完成整个filter的流程。

follow()-> grep() : send() 
grep() -> printer():send()

示例2:作为broadcasting使用

@coroutine
def broadcast(targets):
    while True:
        item = (yield)
        for target in targets:
            target.send(item)
        
        
f = open("access-log")
p = printer()
follow(f,
    broadcast([grep('python',p),
    grep('ply',p),
    grep('swig',p)])
)

这样就将不同的pattern传入到了不同的coroutine中去,达到了broadcast的目的。

follow-> broadcast: send()
broadcast -> grep('python'): send()
broadcast -> grep('ply') : send()
broadcast -> grep('swig') : send()
grep('python') -> printer:
grep('ply')-> printer: 
grep('swig')-> printer:

关于coroutine的更多用法,可见pdf:
http://www.dabeaz.com/coroutines/Coroutines.pdf


posted @ 2016-11-27 15:46  geek精神  阅读(13728)  评论(0编辑  收藏  举报