协程学习笔记
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了协程学习笔记相关的知识,希望对你有一定的参考价值。
一、协程简介
什么是协程?
协程,又称微线程,线程,英文名Coroutine。协程是一种用户态的轻量级线程
协程拥有自己的寄存器上下文和栈。
简单来说,协程就是来回切换,当遇到IO操作,如读写文件,网络操作时,就跳到另一个线程执行,再遇到IO操作,又跳回来。不断的跳过去跳过来执行,因为速度很快,所以看起来就像是执行的并发,实质上是单线程。
协程的好处:
- 无需线程上下文切换的开销
- 无需原子操作锁定及同步的开销
- 方便切换控制流,简化编程模型
- 高并发+高扩展性+低成本
- 一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理
协程的缺点:
1.无法利用多核资源
协程的本质是个单线程,不能同时将单个CPU 的多个核用上。
协程需要和进程配合才能运行在多CPU上,日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用
2.进行阻塞(Blocking)操作(如IO时,读写文件,网络)会阻塞掉整个程序
二、yield实现最简单协程效果
在单线程中实现并发效果
以简单的生产者消费者模型为例,生产者厨师做包子,消费者吃包子
代码1:
说明:1个生产者,每次做1个包子,只做5个,2个消费者
1 import time 2 import queue 3 4 def consumer(name): 5 print("%s准备开始吃包子啦..." % name) 6 while True: 7 new_baozi = yield 8 print("[%s] 正在吃包子 %s" % (name,new_baozi)) 9 #time.sleep(1) 10 11 def producer(): 12 r = con.__next__() 13 r = con2.__next__() 14 n = 0 15 while n < 5: # 生产者只做5个包子 16 n += 1 17 print("\033[32;1m[producer]\033[0m做好了新包子 %s" % n ) 18 time.sleep(1) 19 con.send(n) 20 con2.send(n) 21 22 if __name__ == ‘__main__‘: 23 # 定义2个消费者、1个生产者 24 con = consumer("c1") 25 con2 = consumer("c2") 26 p = producer() 27 28 # 显示结果: 29 # c1准备开始吃包子啦... 30 # c2准备开始吃包子啦... 31 # [producer]做好了新包子 1 32 # [c1] 正在吃包子 1 33 # [c2] 正在吃包子 1 34 # [producer]做好了新包子 2 35 # [c1] 正在吃包子 2 36 # [c2] 正在吃包子 2 37 # [producer]做好了新包子 3 38 # [c1] 正在吃包子 3 39 # [c2] 正在吃包子 3 40 # [producer]做好了新包子 4 41 # [c1] 正在吃包子 4 42 # [c2] 正在吃包子 4 43 # [producer]做好了新包子 5 44 # [c1] 正在吃包子 5 45 # [c2] 正在吃包子 5
代码2:
说明:生产者只做5次包子,每次2个,2个消费者
1 import time 2 import queue 3 4 def consumer(name): 5 print("%s准备开始吃包子啦..." % name) 6 while True: 7 new_baozi = yield 8 print("[%s] 正在吃包子 %s" % (name,new_baozi)) 9 #time.sleep(1) 10 11 def producer(name): 12 r = con.__next__() 13 r = con2.__next__() 14 n = 0 15 m = 0 16 count = 0 17 while count < 5: # 生产者只做5次包子,每次2个 18 n = m + 1 19 m = n + 1 20 count += 1 21 print("\033[32;1m厨师%s\033[0m做好了新包子 %s" % (name,n) ) 22 print("\033[32;1m厨师%s\033[0m做好了新包子 %s" % (name,m) ) 23 time.sleep(1) 24 con.send(n) 25 con2.send(m) 26 27 if __name__ == ‘__main__‘: 28 # 定义2个消费者、1个生产者 29 con = consumer("莉莉") 30 con2 = consumer("静静") 31 p = producer("小白") 32 33 # 显示结果: 34 # 莉莉准备开始吃包子啦... 35 # 静静准备开始吃包子啦... 36 # 厨师小白做好了新包子 1 37 # 厨师小白做好了新包子 2 38 # [莉莉] 正在吃包子 1 39 # [静静] 正在吃包子 2 40 # 厨师小白做好了新包子 3 41 # 厨师小白做好了新包子 4 42 # [莉莉] 正在吃包子 3 43 # [静静] 正在吃包子 4 44 # 厨师小白做好了新包子 5 45 # 厨师小白做好了新包子 6 46 # [莉莉] 正在吃包子 5 47 # [静静] 正在吃包子 6 48 # 厨师小白做好了新包子 7 49 # 厨师小白做好了新包子 8 50 # [莉莉] 正在吃包子 7 51 # [静静] 正在吃包子 8 52 # 厨师小白做好了新包子 9 53 # 厨师小白做好了新包子 10 54 # [莉莉] 正在吃包子 9 55 # [静静] 正在吃包子 10
用sleep,模拟IO操作阻塞
一遇到阻塞,怎么把阻塞丢给操作系统,yield实现不了,用协程可以实现
三、greenlet模块
greenlet,协程模块,是一个第三方模块,不是Python自带的,需要安装才能够使用。
导入模块命令:from greenlet import greenlet
代码示例:
1 from greenlet import greenlet 2 3 def test1(): 4 print(12) 5 gr2.switch() 6 print(34) 7 gr2.switch() 8 9 def test2(): 10 print(56) 11 gr1.switch() 12 print(78) 13 14 gr1 = greenlet(test1) 15 gr2 = greenlet(test2) 16 gr1.switch() 17 18 # 显示结果: 19 # 12 20 # 56 21 # 34 22 # 78 23 24 # 说明:先执行test1函数,打印了12,切换到test2函数,打印出56,再返回到test1(先前切换的地方),打印34,又切换到test,打印78 25 # 协程,就是来回的切换
先写到这里...
以上是关于协程学习笔记的主要内容,如果未能解决你的问题,请参考以下文章