概念
协程,又称微线程。英文名Coroutine。
子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。所以子程序调用是通过栈实现的,一个线程就是执行一个子程序。
协程不同于线程,线程是抢占式的调度,而协程是协同式的调度,协程需要自己做调度。
子程序调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。
协程优势是极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。用来执行协程多任务非常合适。
协程没有线程的安全问题。一个进程可以同时存在多个协程,但是只有一个协程是激活的,而且协程的激活和休眠又程序员通过编程来控制,而不是操作系统控制的。
因为协程是一个线程中执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
Python对协程的支持是通过generator实现的。在generator中,我们不但可以通过for循环来迭代,还可以不断调用next()函数获取由yield语句返回的下一个值。但是Python的yield不但可以返回一个值,它还可以接收调用者发出的参数。
使用
用协程来解决生产者消费者问题。
# coding: utf-8
def consumer():
r = ''
while 1:
n = yield r
if not n:
break
print 'consumer receive msg: %s' % n
r = '%s OK' % n
def produce():
c = consumer()
c.send(None)
n = 0
while n < 3:
n += 1
print 'produce send msg: %s' % n
r = c.send(n)
print 'consumer return msg: %s' % r
c.close()
produce()
执行结果
produce send msg: 1
consumer receive msg: 1
consumer return msg: 1 OK
produce send msg: 2
consumer receive msg: 2
consumer return msg: 2 OK
produce send msg: 3
consumer receive msg: 3
consumer return msg: 3 OK
执行过程分析:
1. consumer函数是一个generator。
2. c.send(None)其实等价于next(c),第一次执行时其实只执行到n = yield r就停止了,然后把r的值返回给调用者。
3. yield r是一个表达式,通过send(msg)被赋值,而send(msg)是有返回值的,返回值为:下一个yield r表达式的参数,即为r。
4. produce一旦生产了东西,通过c.send(n)切换到consumer执行。consumer通过yield拿到消息,处理,又通过yield把结果传回。也就是说,c.send(1) 不但会给 c 传送一个数据,它还会等着下次 yield 从 c 中返回一个数据,它是有返回值的,一去一回才算完,拿到了返回的数据(200 OK)才继续下面执行。
5. 整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。
小结
TODO