1、协程的优势
当使用多线程或多进程处理耗时操作时,线程或进程间的调度靠操作系统,但操作系统对线程或进程的调度是消耗资源的
协程其实就是将调度的过程让程序员处理,从而减少资源的消耗,让程序更快。协程不需要考虑同步机制,如锁、信号量等
协程是一种用户状态的轻量级线程,本质上是单线程,拥有自己的寄存器上下文和栈,所以能保留上一次调用时的状态,每次过程重入时,
就相当于进入上一次调用的状态。
与多进程相比,无需上下文切换的开销,与多线程相比,无需使用多线程的锁机制。执行效率要高于多线程和多进程
2、yield from
def consumer():
r = ''
while True:
n = yield r#获得生产者传过来的r
if not n:
return
print(f'[消费者] 消费{n}')
r = '200 ok'
def produce(c):
c.send(None)#预激活
n = 0
while n<5:
n = n+1
print(f'[生产者] 产生 {n} 数据')
r = c.send(n)
print(f'[生产者]消费者返回值:{r}')
c.close()#关闭协程对象
c = consumer()
produce(c)
def gen():
for i in range(1,3):
yield i
for y in range(4,6):
yield y
print(list(gen()))
#嵌套生成器不必通过循环迭代yield,可以直接使用yield from
def gen2():
yield from range(1,3)
yield from range(4,6)
print(list(gen2()))
在生成器gen中使用yield from subgen(子生成器)时,subgen会获得控制权,把产出的值传给gen的调用方,即调用方可以直接控制subgen
yield from主要功能是打开双通道,把最外层的调用方与最内层的子生成器连接起来,二者可直接发送和产出值。
from collections import namedtuple
data = {
'girls;kg':[40.9,38.5,44.3,45.2],
'girls;m':[1.6,1.51,1.4,1.3]
}
Result = namedtuple('Result','count average')
#客户端代码即调用方
def main(data):
results = {}
for key,values in data.items():#group是调用grouper函数得到的生成器对象,传给grouper函数的第一个参数是results,用于收集结果
group = grouper(results,key)
next(group)
for value in values:
group.send(value)
group.send(None)
report(results)
#委派生成器
def grouper(results,key):
while True:
results[key] = yield from make_avg()
#子生成器
def make_avg():
'''
计算移动平均值
:return:
'''
total = 0
count = 0
avg = None
while True:
term = yield
if term is None:
break
total += term
count += 1
avg = total / count
return Result(count,avg)
def report(results):
for key,result in sorted(results.items()):
group,unit = key.split(';')
print(f'{result.count}{group} averaging {result.average}{unit}')
main(data)