协同程序可以挂起、恢复,并且有多个接入点的函数。有些语言本省就提供了这种特性,如Io语言和Lua语言,它们可以实现协同的多任务和管道机制。例如,每个协同程序将消费或生成数据,然后暂停,直到其他数据被传递。在Python中,协同程序的替代者是线程,它可以实现代码块之间的交互。但是因为它们表现出一种抢先式的风格,所以必须注意资源锁,而协同程序不需要。这样的代码可能变得相当复杂,难以创建和调试。但是生成器几乎就是协同程序,添加send、throw和close,其初始的意图就是为该语言提供一种类似协同程序的特性。
PEP342实例化了生成器的新行为,也提供了创建协同程序的调度程序的完整实例。这个模块称为Trampoline,可以看做生成和消费数据的协同程序之间的媒介。它使用一个队列将协同程序连接在一起。在PyPI中的multitask模块实现了这一模式,使用也十分简单,如下:
import multitask
import time
def coroutine_1():
for i in range(3):
print 'c1'
yield i
def coroutine_2():
for i in range(3):
print 'c2'
yield i
multitask.add(coroutine_1())
multitask.add(coroutine_2())
multitask.run()
结果为:
c1
c2
c1
c2
c1
c2
经典的生产者-消费者问题就可以使用协同程序来实现,比多线程更为高效:
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print 'consumer %s' % n
r = 'OK'
def producer(c):
c.next()
n = 0
while n < 5:
n += 1
print 'producer %s' % n
r = c.send(n)
print 'consumer return %s' % r
c.close()
if __name__ == '__main__':
c = consumer()
producer(c)
结果为:
producer 1
consumer 1
consu