协程

协程具有极高的执行效率,因为子程序切换不是线程切换,而是由程序控制,
没有线程切换的开销,和多线程比,线程数量越多,性能优势越明显。
因为只有一个线程,不存在同时写变量冲突,在协程中控制共享资源只需要判断状态,
不必加锁,故执行效率比多线程高。
协程是一个线程执行,使用多进程+协程,可充分利用多核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()
View Code

【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()
View Code

【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)
View Code
原文地址:https://www.cnblogs.com/mountain2011/p/11361029.html