并发编程——协程(5)
1.协程
- 协程:是单线程下的并发,又称微线程;协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
- 优点
- 1.协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
- 2、单线程内就可以实现并发的效果,最大限度地利用CPU
- 缺点:
- 1.协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
- 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
- 特点总结:
- 1.必须在只有一个单线程里实现并发
- 2.修改共享数据不需加锁
- 3.用户程序里自己保存多个控制流的上下文栈
- 4.一个协程遇到IO操作自动切换到其他协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))
2.greenlet模块
- 优点:比generator便捷
- 缺点:当切刀一个任务执行时如果遇到io,那就原地阻塞,仍然是没有解决遇到IO自动切换来提升效率的问题
-
1 #-*- coding:utf-8 -*- 2 # greenlet : 遇IO切不了 3 from greenlet import greenlet 4 import time 5 def eat(name): 6 print("%s eat 1"%name) 7 time.sleep(3)#遇IO不切 8 g2.switch("egon")#第一次需传参数 9 print("%s eat 2"%name) 10 g2.switch() 11 def play(name): 12 print("%s play 1"%name) 13 g1.switch() 14 print("%s play 2"%name) 15 g1 = greenlet(eat) 16 g2 = greenlet(play) 17 g1.switch("egon")
3.gevent模块
-
1 # 2 # import gevent 3 # import time 4 # #gevent 只能切自己的IO 5 # def eat(name): 6 # print("%s eat 1"%name) 7 # gevent.sleep(3) 8 # print("%s eat 2"%name) 9 # def play(name): 10 # print("%s play 1"%name) 11 # gevent.sleep(4) 12 # print("%s play 2"%name) 13 # start_time = time.time() 14 # g1 = gevent.spawn(eat,'egon') 15 # g2 = gevent.spawn(play,'alex') 16 # 17 # g1.join() 18 # g2.join() 19 # end_time = time.time() 20 # print(end_time-start_time) 21 22 # 解决gevent只能切自己IO的方法 23 from gevent import monkey 24 monkey.patch_all() 25 import gevent 26 import time 27 def eat(name): 28 print("%s eat 1"%name) 29 # gevent.sleep(3) 30 time.sleep(3) 31 print("%s eat 2"%name) 32 def play(name): 33 print("%s play 1"%name) 34 # gevent.sleep(4) 35 time.sleep(4) 36 print("%s play 2"%name) 37 start_time = time.time() 38 g1 = gevent.spawn(eat,'egon') 39 g2 = gevent.spawn(play,'alex') 40 41 g1.join() 42 g2.join() 43 # gevent.joinall() 44 end_time = time.time() 45 print(end_time-start_time)