引言:
- 笔者最近在学习协程和yield使用的相关知识和案例的情况下, 发现了yield from在python2里面是不支持的, 所以所看的论文上的yield from的使用方法在python2里面根本跑不起来.
- 这里面无法复用原代码的让我很纠结的原因就是 迭代器函数调用send({value})这个方法的时候如果是多个yield迭代的情况下, 没办法正常的将send里面的值传递过去, 所以有了以下的一个粗暴实现…
# 子生成器
def average_gen():
total = 0
count = 0
average = 0
while True:
new_num = yield average
count += 1
total += new_num
average = total/count
# 委托生成器
def proxy_gen():
x = average_gen()
# 方法一: 使用计数器, 正常情况下第一次预激活的时候m是没有被定义的, 通过次数来判断
c = 0
while True:
m = yield x.send(m if c else None)
c += 1
# 方法二: 直接try catch来检查
try:
m = yield x.send(m)
except UnboundLocalError:
m = yield x.send(None)
# 调用方
def main():
calc_average = proxy_gen()
calc_average.send(None) # 预激下生成器
print "放飞自我"
print calc_average.send(10) # 打印:10.0
print calc_average.send(20) # 打印:15.0
print calc_average.send(30) # 打印:20.0
calc_average.close() # 关闭协程,如果不关闭, 则该协程将一直挂起
if __name__ == '__main__':
main()
两种方式的生产者消费者模型
传统的
import time
import random
from multiprocessing import Queue, Process
def consumer(name, q):
while True:
res = q.get()
time.sleep(random.randint(1, 3))
print('消费者》》%s 准备开吃%s。' % (name, res))
def producer(name, q):
i = 0
while 1:
time.sleep(random.randint(1, 2))
i += 1
res = '大虾%s' % i
q.put(res)
print('生产者》》》%s 生产了%s' % (name, res))
if __name__ == '__main__':
q = Queue() # 一个队列
p1 = Process(target=producer, args=('monicx', q))
c1 = Process(target=consumer, args=('lili', q))
p1.start()
c1.start()
先科普点小知识
Python multiprocessing.Queue 和 Queue区别
- Queue是python自带的标准库,支持线程安全,所以多线程下可以随意使用,不会出现写冲突。
- multiprocessing.Queue这个multiprocessing模块封装的,它支持多进程之间的交互,比如master-worker模式下,master进程写入,work进程消费的模式,支持进程之间的通信。也就是进程安全
- 无论是线程安全还是进程安全, 都是内部通过加锁实现的, 即会损失一些性能.
协程
缺点:感觉这种方式去实现耦合的太紧了.
def consumer(name, producer):
while True:
res = next(producer)
print('消费者》》%s 准备开吃%s。' % (name, res))
def producer(name):
i = 0
while 1:
i += 1
res = '大虾%s' % i
print('生产者》》》%s 生产了%s' % (name, res))
yield i
if __name__ == '__main__':
producer = producer('lily')
consumer('didi', producer)