3.4.1 Greenlet
协程
协程,又称微线程,纤程。英文名coroutine。简单说:协程是一种用户态的轻量级线程。
协程拥有自己的寄存器上下文和栈。写成调度切换时,将寄存器上下文和栈保存到其他地方,在且回来的时候,恢复先前保存的寄存器上下文和栈。
因此,协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换句话说:进入上一次离开时所处逻辑流的位置。
协程的优点:
- 无需线程上下文切换的开销
- 无需原子操作锁定及同步的开销 #改一个变量就是原子操作
- 方便切换控制流,简化编程模型
- 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
缺点:
- 无法利用多核资源:协程的本质是个单线程,它不能同时将单个CPU的多个核用上,协程需要和进程配合才能运行在多核CPU上,当然我们日常所编写的绝大部分应用都没有这个必要,除非是CPU密集型应用。
- 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
下面是一个使用yield实现协程的示例
import time, queue def consumer(name): #函数中使用yield语句,函数会变成一个生成器 print('Starting to sell iphone...') #2.1输出 3.1输出 while True: new_iphone = yield #2.2返回 3.2返回 print('%s bought a iphone %s' % (name, new_iphone)) #4.1 c1收到参数并输出 5.1 c2收到参数并输出 time.sleep(1) #4.2 c1睡1秒 5.2 c2睡1秒 def producer(): r = c1.__next__() #2 执行c1 r = c2.__next__() #3执行c2 n = 0 while n < 5: n += 1 c1.send(n) #4 c1传参n并返回至c1yield c2.send(n) #5 c2传参n并返回至c2yield print('[Producer] is producing iphone %s.' % n) #6输出 if __name__ == '__main__': #------>从这里开始 c1 = consumer('c1') #生成器c1 c2 = consumer('c2') #生成器c2 p = producer() #1 实例化并执行
结果
Starting to sell iphone... Starting to sell iphone... c1 bought a iphone 1 c2 bought a iphone 1 [Producer] is producing iphone 1. c1 bought a iphone 2 c2 bought a iphone 2 [Producer] is producing iphone 2. c1 bought a iphone 3 c2 bought a iphone 3 [Producer] is producing iphone 3. c1 bought a iphone 4 c2 bought a iphone 4 [Producer] is producing iphone 4. c1 bought a iphone 5 c2 bought a iphone 5 [Producer] is producing iphone 5.
以上就是使用yield实现一个协程的例子。
协程的标准定义:
- 必须在只有一个单线程里实现开发
- 修改共享数据不需加锁
- 用户程序里自己保存多个控制流的上下文栈
- 一个协程遇到IO操作自动切换到其他协程
基于以上4点,上面的示例严格说还不算真正的协程,因为它有一个功能没实现。
Greenlet
greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator
from greenlet import greenlet #greenlet手动切换协程 def test1(): print(12) #2 gr2.switch() print(34) #4 gr2.switch() def test2(): print(56) #3 gr1.switch() print(78) #5 gr1 = greenlet(test1) #启动gr1协程 gr2 = greenlet(test2) #启动gr2协程 gr1.switch() #1
结果
12 56 34 78
感觉确实用着比generator还简单了呢,但好像还没有解决一个问题,就是遇到IO操作,自动切换,对不对?