Python并发实践_02_通过yield实现协程
python中实现并发的方式有很多种,通过多进程并发可以真正利用多核资源,而多线程并发则实现了进程内资源的共享,然而Python中由于GIL的存在,多线程是没有办法真正实现多核资源的。
对于计算密集型程序,应该使用多进程并发充分利用多核资源,而在IO密集型程序中,多核优势并不明显,甚至由于大多数时间都是在IO堵塞状态,多进程的切换消耗反而让程序效率更加低下。
而当需要并发处理IO密集型任务时,就需要用到协程(Coroutine)。协程并没有系统级的调度,而是用户级的调度方式,避免了系统调用的开销,虽然协程最终是串行工作,但是却可以实现非常大的并发量。通过多进程+协程的方式,可以有效均衡多核计算和请求等待。
参考文章:
https://blog.tonyseek.com/post/event-manage-with-greenlet/
producer-consumer
利用yield生成器,可以简单展现协程的工作方式:
import time
def consumer():
print "Ready to receive"
while True:
y = (yield )
time.sleep(1)
print "Receive %s from producer”%y
def producer():
c = consumer()
c.next()
i = 1
while i > 0 and i < 11:
time.sleep(1)
print "Send %s to consumer"%i
c.send(i)
i += 1
if __name__ == '__main__':
producer()
上述过程展示了基本的生产者-消费者模型,消费者consumer是一个生成器;
当第一次在producer中调用c.next()时,激活consumer,并且运行到yield时协程(consumer)被挂起,等待生成器被调用next或者send。
producer进行后续操作,并进入一个循环,每次暂停1s后,向生成器send一个消息,消费者yield获取到该消息,并进行后续的工作。
可以看到,每次yield都需要等待send传入的消息之后才会继续执行之后的任务。
通过yield实现协程
现在要来用yield真正创建一个协程了。
可以想象这样一个模型,一个工地里有很多相似的任务(jobs),并且会源源不断产生这些任务,工地里有一个工头(foreman)负责,工头为了分配任务给工人(worker),会制定一套流程(pipeline)来方便管理:分配工人,验收工作(accept),由于工人工作(work)的时间远远大于分配任务的时间,将这些工人的工作(简单枯燥的重复劳动)看成IO操作的话,这就是一个IO密集型的任务。下面看看python是如何通过yield来实现协程完成真个工作的:
def main():
foreman(args_of_overall,worker_num) def foreman(args_of_overall,worker_num):
pipeline = create_pipeline(args_of_pipeline,worker_num)
for i,job in enumerate(get_jobs(args_of_ceate_jobs)):
worker_id = i % worker_num
pipeline.send((job,worker_id)) @coroutine
def worker(pipeline,accepting,job,my_id):
while True:
args_of_job, worker_id = (yield )
if worker_id == my_id:
result = work(args_of_job)
accepting.send(result)
elif pipeline is not None:
pipeline.send((job,worker_id)) @coroutine
def accept():
while True:
result = (yield )
#do_some_accepting def create_pipeline(args_of_pipeline,worker_num):
pipeline = None
accepting = accept()
for work_id in range(work_num):
pipeline = worker(pipeline,accepting,job,work_id)
return pipeline def get_jobs(args_of_ceate_jobs):
for job in job_source:
yield job def coroutine(func):
def warper(*args):
f = func(*args)
f.next()
return f
return warper def work(args_of_job):
pass
#do_some_work if __name__ == '__main__':
main()
上述过程中,工人和验收工作都是协程,而get_jobs()函数是一个生成器,当job是动态添加时,就可以改写成一个协程。
上述所有的工作都是串行完成,虽然有很多工人,工人之间的工作是并发的(IO等待时间),但是工作一直是从第一个开始一个一个分配任务。
Python并发实践_02_通过yield实现协程的更多相关文章
- Python并发编程二(多线程、协程、IO模型)
1.python并发编程之多线程(理论) 1.1线程概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程(流水线的工作需要电源,电源就相当于 ...
- python并发编程-进程池线程池-协程-I/O模型-04
目录 进程池线程池的使用***** 进程池/线程池的创建和提交回调 验证复用池子里的线程或进程 异步回调机制 通过闭包给回调函数添加额外参数(扩展) 协程*** 概念回顾(协程这里再理一下) 如何实现 ...
- python 并发专题(六):协程相关函数以及实现(gevent)
文档资源 http://sdiehl.github.io/gevent-tutorial/ 一.协程实现 线程和协程 既然我们上面也说了,协程也被称为微线程,下面对比一下协程和线程: 线程之间需要上下 ...
- python教程:使用 async 和 await 协程进行并发编程
python 一直在进行并发编程的优化, 比较熟知的是使用 thread 模块多线程和 multiprocessing 多进程,后来慢慢引入基于 yield 关键字的协程. 而近几个版本,python ...
- Python开发【第九篇】:协程、异步IO
协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程,协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切换回 ...
- Python、进程间通信、进程池、协程
进程间通信 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的. 进程队列queue 不同于线程queue,进程 ...
- (转)Python黑魔法 --- 异步IO( asyncio) 协程
转自:http://www.jianshu.com/p/b5e347b3a17c?from=timeline Python黑魔法 --- 异步IO( asyncio) 协程 作者 人世间 关注 201 ...
- 深入浅析python中的多进程、多线程、协程
深入浅析python中的多进程.多线程.协程 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源 ...
- python基础之进程、线程、协程篇
一.多任务(多线程) 多线程特点:(1)线程的并发是利用cpu上下文的切换(是并发,不是并行)(2)多线程执行的顺序是无序的(3)多线程共享全局变量(4)线程是继承在进程里的,没有进程就没有线程(5) ...
随机推荐
- 50个php程序性能优化集锦
1. 用单引号代替双引号来包含字符串,这样做会更快一些.因为 PHP 会在双引号包围的 字符串中搜寻变量,单引号则不会,注意:只有 echo 能这么做,它是一种可以把多个字符 串当作参数的" ...
- MongoDb安装--yum安装
本帖最后由 草包 于 2017-5-2 09:57 编辑 [Shell] 纯文本查看 复制代码 ? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 ...
- javascript设计模式——中介者模式
前面的话 程序由大大小小的单一对象组成,所有这些对象都按照某种关系和规则来通信.当程序的规模增大,对象会越来越多,它们之间的关系也越来越复杂,难免会形成网状的交叉引用.当改变或删除其中一个对象的时候, ...
- NOI导刊2010提高装备运输
www.luogu.org/problem/show?pid=1794 挺裸的一题背包,算很基础. 可以运用的技巧是三维->二维(节省空间还能少敲一点代码 #include<iostrea ...
- 学校的c++程序课程设计(简单的写法 并无太多c++的特色)
好久没更新博客了,最近一直在忙,花了一天时间做出这个简陋版的课程设计, 为了储存,也为了更新,所以于今天更新我的博客. 我选的课程设计题目如下: 某某公司的设备管理系统 功能及要求描述: (1)公司主 ...
- C++ IO操作API及注意事项(包含一个日志类的实现)
C++是一个抽象程度比C高很多的语言,在使用C++时,编译器做了很多工作,如果我们不对C++的某些特性的实现机制进行了解,那么编程时也许会有很多疑惑,我们也许知道怎样做才是正确的,但不知道为什么要这样 ...
- 载入DLL中的图片资源生成Skia中的SkBitmap对象
PPAPI Plugin在Windows下是DLL,能够嵌入图片文件.使用Skia画图时须要依据DLL里的图片文件生成SkBitmap对象. 以下是代码: #include "utils.h ...
- 关于子线程更新UI
大家都了解的子线程不能更新UI,所以普通青年比方我,遇到耗时操作用到线程时.不得不立刻想到了用handler传递来解决UI更细的问题. 普通青年的做法: 方案:使用Thread+handler方式,h ...
- Django的Models(二)映射关系
关系分为三种: 一对一 :user2 = models.OneToOneField("UserInfo") 一对多:user = models.ForeignKey("U ...
- IDEA Translation插件中有道智云(有道翻译)应用ID,密钥申请教程
登录链接 该登录登录,该注册注册(信息随意填写) 自然语言翻译=>翻译实例=>创建实例(信息随意填写) QQ截图20170701231552.png 应用管理=>我的应用=>创 ...