简介
- 什么是协程?
- 协程又称为微线程,是比线程小的运行单位,自带CPU上下文
- CPU上下文
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()
while True:
next(g1)
next(g2)
**代码解析:**<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)
- 再函数的循环中使用yield可以创建生成器,步骤1并不会调用该函数只是创建生成器
- 当第一次启动生成器时便调用了func1和func2,执行到yield语句时,函数返回值,挂起
- 等待主程序第二次循环的时候,再次调用func1和func2,从yield语句开始执行
<a name="pwsA0"></a>
#### yield from双向通道
```python
def func():
num = 0
while True:
num += 1
print(num)
w = yield num
print(w)
if w == "":
break
g = func()
next(g)
g.send("hi")
g.send("hello")
g.send("")
运行结果:
- send方法可以与函数进行传值,同时再次使用生成器
- 第一次使用生成器需要使用next方法,否则会报错,因为第一次使用的时候,程序执行到yield就会被挂起,由于等于号,程序是由左至右运行的,所以没有变量来接受send过去的值
- 相当于生产者已经生产了数据,然乎通过send将数据传递给消费者func函数
def func():
num = 0
while True:
num += 1
print(num)
w = yield num
print(w)
if w == "":
break
def generator():
yield from func()
g = func()
next(g)
g.send("hi")
g.send("hello")
g.send(None)
- yield from主要作用是打开双向通道,可以铺获异常
greenlet实现协程
- 需要手动切换任务 ```python from greenlet import greenlet
def func1(): for _ in range(3): print(“func1 over”)
# 任务切换到g2
g2.switch()
def func2(): for _ in range(3): print(“func2 over”)
# 任务切换到g1
g1.switch()
if name == ‘main‘:
# 创建协程
g1 = greenlet(func1)
g2 = greenlet(func2)
# 切换到g1
g1.switch()
print("all over")
![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)
<a name="OaUDX"></a>
#### gevent实现协程
- 再遇到IO操作时不需要手动切换任务
```python
import gevent
def func1(n):
for _ in range(n):
print(gevent.getcurrent())
gevent.sleep(1)
def func2(n):
for _ in range(n):
# 查看当前协程
print(gevent.getcurrent())
# IO延时
gevent.sleep(1)
if __name__ == '__main__':
g1 = gevent.spawn(func1, 5)
g2 = gevent.spawn(func2, 4)
g1.join()
g2.join()