- 无限列表
def fib():
first, second = 0, 1
yield first
yield second
while True:
third = first + second
yield third
first = second
second = third
- 管道
import os
import fnmatch
import gzip, bz2
def coroutine(func):
"""自动调用协程的next()函数"""
def start(*args, **kwargs):
g = func(*args, **kwargs)
g.next()
return g
return start
@coroutine
def find_files(target):
while True:
topdir, pattern = (yield)
for path, dirname, filelist in os.walk(topdir):
for name in filelist:
if fnmatch.fnmatch(name, pattern):
target.send(os.path.join(path, name))
@coroutine
def opener(target):
while True:
name = (yield)
if name.endswith('.gz'): f = gzip.open(name)
elif name.endswith('.bz2'): f = bz2.BZ2File(name)
else: f = open(name)
target.send(f)
@coroutine
def cat(target):
while True:
f = (yield)
for line in f:
target.send(line)
@coroutine
def grep(pattern, target):
while True:
line = (yield)
if pattern in line:
target.send(line)
@coroutine
def printer():
while True:
line = (yield)
sys.stdout.write(line)
finder = find_files(opener(cat(grep('python', printer))))
finder.send('www', 'access-log*')
finder.send('otherwww', 'access-log*')
- 并发
最好的例子应该是gevent吧,大家有兴趣可以看下源码。基本的原理是,将函数变为协程,每触发I/O阻塞就yield交出控制权,并将事件注册到epoll,当I/O就绪就是用send方法,传入I/O数据,并恢复逻辑。这么描述其实和tornado、nodejs的网络模型很像,但是协程对于程序员更加友好。tornado和nodejs默认还是通过回调函数完成这个事件循环的,这样代码并不直观,但使用协程可以用同步的方式完成回调函数的工作。