共计 1463 个字符,预计需要花费 4 分钟才能阅读完成。
一、概念
-
子程序
在所有的语言中都是层级调用的,比如 A 中调用 B,B 在执行过程中调用 C,C 执行完返回,B 执行完返回,最后是 A 执行完毕。这是通过栈实现的,一个函数就是一个执行的子程序,子程序的调用总是有一个入口、一次返回,调用的顺序是明确的
-
协程
又称微线程(纤程),是一种用户态的轻量级线程
-
理解协程
普通理解:线程是系统级别的,它们是由操作系统调度。协程是程序级别,由程序员根据需求自己调度。我们把一个线程中的一个个函数称为子程序,那么一个子程序在执行的过程中可以中断去执行别的子程序,这就是协程。也就是说同一个线程下的一段代码 1 执行执行着就中断,然后去执行另一段代码 2,当再次回来执行代码 1 时,接着从之前的中断的位置继续向下执行
专业理解:协程拥有自己的寄存器上下文和栈,协程在调度切换时,将寄存器上下文和栈保存到其他的地方,在切换回来时,恢复先前保存的寄存器上下文和栈。因此,协程能后保留一次调用的状态,每次过程重入时,就相当于进入上一次调用的状态
-
优点
a、无需线程上下文切换的开销,协程避免了无意义的调度,从而提高了性能,但是程序员必须自己承担调度的任务,同时协程也失去了标准线程使用多 CPU 的能力
b、无需原子操作锁定及同步的开销
c、方便切换控制流,简化编程模型
d、高并发 + 高可扩展 + 低成本:一个 CPU 支持上万个协程不是问题
-
缺点
a、无法利用多核 CPU,协程的本质是单个线程,它不能同时将多个 CPU 的多个核心使用上,协程需要和进程匹配使用才能运行在多个 CPU 上。但是一般不需要,除非是 CPU 计算密集型的应用
b、进行阻塞操作 (操作 IO) 会阻塞整个程序
-
代码
def run1(): print(1) print(2) print(3) print(4) def run2(): print("a") print("b") print("c") print("d") run1() run2()
-
结果
正常结果
1 2 3 4 a b c d
协程实现的结果(假设)
1 a b 2 3 c 4 d
二、数据传递
-
数据传递
def func(): print("------------------1") r = yield 1 print("------------------2", r) yield 2 print("------------------3") yield 3 print("------------------4") yield 4 print("------------------5") yield 5 g = func() # print(next(g)) # print(next(g)) # print(next(g)) # print(next(g)) # print(next(g)) # 启动生成器 g,从第二个开始 send 的参数值会放到 yield 处 print(g.send(None)) print(g.send(11))
-
生产者与消费者
import time def product(c): print("启动生产者……") # 启动消费者 c.send(None) for data in ["good", "nice", "cool", "handsome"]: print("生产出 %s 数据"%(data)) # 将数据交给消费者 c.send(data) time.sleep(2) # 关闭消费者 c.close() print("结束生产者……") def customer(): print("启动消费者……") while True: print("等待生产者生产数据") # 获取数据 value = yield print("消费了 %s"%value) c = customer() product(c)