简介

  • 什么是协程?
    • 协程又称为微线程,是比线程小的运行单位,自带CPU上下文
  • CPU上下文
    • CPU寄存器
      • 内存小、速度快
    • 程序计数器
      • 储存cpu正在执行的指令和要执行的指令

        yield实现协程

        ```python import time

def func1(): while True: print(“func1 running…”) time.sleep(1) yield

def func2(): while True: print(“func2 running…”) time.sleep(1) yield

if name == ‘main‘: g1 = func1() g2 = func2()

  1. while True:
  2. next(g1)
  3. next(g2)
  1. **代码解析:**<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/1325594/1594282664367-92768910-17ef-4546-93f8-c48a1e607a4a.png#align=left&display=inline&height=486&margin=%5Bobject%20Object%5D&name=image.png&originHeight=646&originWidth=1122&size=48038&status=done&style=none&width=844)<br />**运行结果:**<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/1325594/1594282887165-f70661bd-c483-44f6-9b70-375e8914ec16.png#align=left&display=inline&height=174&margin=%5Bobject%20Object%5D&name=image.png&originHeight=287&originWidth=1396&size=57224&status=done&style=none&width=844)
  2. - 再函数的循环中使用yield可以创建生成器,步骤1并不会调用该函数只是创建生成器
  3. - 当第一次启动生成器时便调用了func1func2,执行到yield语句时,函数返回值,挂起
  4. - 等待主程序第二次循环的时候,再次调用func1func2,从yield语句开始执行
  5. <a name="pwsA0"></a>
  6. #### yield from双向通道
  7. ```python
  8. def func():
  9. num = 0
  10. while True:
  11. num += 1
  12. print(num)
  13. w = yield num
  14. print(w)
  15. if w == "":
  16. break
  17. g = func()
  18. next(g)
  19. g.send("hi")
  20. g.send("hello")
  21. g.send("")

运行结果:
image.png

  • send方法可以与函数进行传值,同时再次使用生成器
  • 第一次使用生成器需要使用next方法,否则会报错,因为第一次使用的时候,程序执行到yield就会被挂起,由于等于号,程序是由左至右运行的,所以没有变量来接受send过去的值
  • 相当于生产者已经生产了数据,然乎通过send将数据传递给消费者func函数
  1. def func():
  2. num = 0
  3. while True:
  4. num += 1
  5. print(num)
  6. w = yield num
  7. print(w)
  8. if w == "":
  9. break
  10. def generator():
  11. yield from func()
  12. g = func()
  13. next(g)
  14. g.send("hi")
  15. g.send("hello")
  16. g.send(None)

image.png

  • yield from主要作用是打开双向通道,可以铺获异常

Python多任务-协程 - 图3

greenlet实现协程

  • 需要手动切换任务 ```python from greenlet import greenlet

def func1(): for _ in range(3): print(“func1 over”)

  1. # 任务切换到g2
  2. g2.switch()

def func2(): for _ in range(3): print(“func2 over”)

  1. # 任务切换到g1
  2. g1.switch()

if name == ‘main‘:

  1. # 创建协程
  2. g1 = greenlet(func1)
  3. g2 = greenlet(func2)
  4. # 切换到g1
  5. g1.switch()
  6. print("all over")
  1. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1325594/1594300523490-b92f9a16-463a-4475-a23d-99948edf32dd.png#align=left&display=inline&height=114&margin=%5Bobject%20Object%5D&name=image.png&originHeight=169&originWidth=1240&size=38991&status=done&style=none&width=837)
  2. <a name="OaUDX"></a>
  3. #### gevent实现协程
  4. - 再遇到IO操作时不需要手动切换任务
  5. ```python
  6. import gevent
  7. def func1(n):
  8. for _ in range(n):
  9. print(gevent.getcurrent())
  10. gevent.sleep(1)
  11. def func2(n):
  12. for _ in range(n):
  13. # 查看当前协程
  14. print(gevent.getcurrent())
  15. # IO延时
  16. gevent.sleep(1)
  17. if __name__ == '__main__':
  18. g1 = gevent.spawn(func1, 5)
  19. g2 = gevent.spawn(func2, 4)
  20. g1.join()
  21. g2.join()

image.png

更多详情: 链接 1 链接 2