协程具有极高的执行效率,因为子程序切换不是线程切换,而是由程序控制,
没有线程切换的开销,和多线程比,线程数量越多,性能优势越明显。
因为只有一个线程,不存在同时写变量冲突,在协程中控制共享资源只需要判断状态,
不必加锁,故执行效率比多线程高。
协程是一个线程执行,使用多进程+协程,可充分利用多核CPU,获得极佳性能。
【1】yield实现协程(生产者消费者)
Python通过yield提供了对协程的基本支持,但是不完全。

1 import time
2
3 def consumer(name):
4 print("准备")
5 while True:
6 result = yield
7 print("[%s] 消费 %s" % (name,result))
8 #time.sleep(1)
9
10 def producer():
11
12 r = con1.__next__()
13 r = con2.__next__()
14 n = 0
15 while 1:
16 time.sleep(1)
17 print("\生产者: %s and %s" %(n,n+1))
18 con1.send(n) #发送给yield,result得到此值。
19 con2.send(n+1)
20 n +=2
21
22
23 if __name__ == '__main__':
24 con1 = consumer("c1") #获得生成器对象
25 con2 = consumer("c2")
26 p = producer()
【2】Greenlet 协程模块
greenlet是一个用C实现的协程模块,相比与python自带的yield,
它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator。

1 from greenlet import greenlet 2 3 4 def test1(): 5 print(1) 6 gr2.switch() 7 print(3) 8 gr2.switch() 9 10 11 def test2(): 12 print(2) 13 gr1.switch() 14 print(4) 15 16 if __name__ == '__main__': 17 gr1 = greenlet(test1) 18 gr2 = greenlet(test2) 19 gr1.switch()
【3】Gevent
Gevent是一种基于协程的第三方Python网络库,通过greenlet实现协程,非标准库,尚存在缺陷。
在python3中有一个官网正在做并且在3.6中已经稳定的库asyncio。
使用gevent,可以获得极高的并发性能,但gevent只能在Unix/Linux下运行。
由于gevent是基于IO切换的协程,编写的Web App代码,不需要引入gevent的包和修改代码,
只需在部署时,用一个支持gevent的WSGI服务器,就可获得数倍的性能提升。
★过程:
当一个greenlet遇到IO操作时,就自动切换到其他的greenlet,等到IO操作完成,再切换回来。
Gevent直接修改标准库里面大部分的阻塞式系统调用,包括socket、ssl、threading和 select等模块,而变为协作式运行,这一过程在启动时通过monkey patch(猴子补丁)完成:

1 #例:
2 from gevent import monkey; monkey.patch_socket()
3 import gevent
4
5 def f(n):
6 for i in range(n):
7 print gevent.getcurrent(), i
8 gevent.sleep(1) #sleep模拟IO
9
10 g1 = gevent.spawn(f, 5)
11 g2 = gevent.spawn(f, 5)
12 g3 = gevent.spawn(f, 5)
13 g1.join()
14 g2.join()
15 g3.join()
16
17 #例:
18 from gevent import monkey; monkey.patch_all()
19 import gevent
20 import urllib2
21 import time
22 start=time.time()
23
24 def f(url):
25 print('GET: %s' % url)
26 resp = urllib2.urlopen(url)
27 data = resp.read()
28 print('%d bytes received from %s.' % (len(data), url))
29
30 gevent.joinall([
31 gevent.spawn(f, 'https://www.python.org/'),
32 gevent.spawn(f, 'https://www.baidu.com/'),
33 gevent.spawn(f, 'https://github.com/'),
34 ])
35
36 print("cost time:",time.time()-start)
