协程是一种实现并行编程的方法。不同于多线程或者多进程编程,各个协程其实还是在一个线程里运行,只是我们可以控制每个协程什么时候运行,什么时候停止,当一个协程停止时让另外的协程运行,从而达到并行计算的效果。运用协程的优点在于,因为所有的协程其实都是运行在一个线程里,因此它减少了在一个个协程间切换的代价,也不必考虑锁的问题。所以协程实现起来还是比较方便和简单的。
下面展示一个最简单的Python协程:
def coroutine():
print "coroutine"
x = 1
n = yield x
print n,x
c = coroutine()
x= c.next()
c.send(5)
输出如下:
coroutine
1
5 1
Traceback (most recent call last):
File "C:\PythonScript\coroutine.py", line 11, in <module>
c.send(5)
StopIteration
上面的代码中,首先生成协程对象c。之后需要执行一下c.next,程序会跑到coroutine函数中第一个yield的地方,并将yeild右边的值传给x。之后不断调用send,并将send中传入的参数赋值给n。当函数调用完毕的时候,会触发StopIteration的异常。
协程对象可以调用close函数,这样就不会触发StopIteration的异常了。
Python可以通过inspect.getgeneratorstate函数来获取协程的执行状态,该函数会返回下述字符串中的一个:
'GEN_CREATED':等待执行
'GEN_RUNNING':正在执行
'GEN_SUSPENED':在yield表达式处暂停
'GEN_CLOSE':执行结束
可以设置一个预激活协程的装饰器,通过该装饰器装饰协程后,就会预先启动next了。
from functools import wraps
def coroutine(func):
@wraps(func)
def primer(*args, **kwargs):
gen = func(args, kwargs)
next(gen)
return gen
return primer
最后展示一组运用协程实现的生产者消费者模型(其实是廖雪峰官网展示的):
import time
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
time.sleep(1)
r = '200 OK'
def produce(c):
c.next()
print "next"
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n)
print('[PRODUCER] Consumer return: %s' % r)
c.close()
if __name__=='__main__':
c = consumer()
produce(c)
输出结果:
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK