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实现协程的更多相关文章

  1. Python并发编程二(多线程、协程、IO模型)

    1.python并发编程之多线程(理论) 1.1线程概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程(流水线的工作需要电源,电源就相当于 ...

  2. python并发编程-进程池线程池-协程-I/O模型-04

    目录 进程池线程池的使用***** 进程池/线程池的创建和提交回调 验证复用池子里的线程或进程 异步回调机制 通过闭包给回调函数添加额外参数(扩展) 协程*** 概念回顾(协程这里再理一下) 如何实现 ...

  3. python 并发专题(六):协程相关函数以及实现(gevent)

    文档资源 http://sdiehl.github.io/gevent-tutorial/ 一.协程实现 线程和协程 既然我们上面也说了,协程也被称为微线程,下面对比一下协程和线程: 线程之间需要上下 ...

  4. python教程:使用 async 和 await 协程进行并发编程

    python 一直在进行并发编程的优化, 比较熟知的是使用 thread 模块多线程和 multiprocessing 多进程,后来慢慢引入基于 yield 关键字的协程. 而近几个版本,python ...

  5. Python开发【第九篇】:协程、异步IO

    协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是协程,协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切换回 ...

  6. Python、进程间通信、进程池、协程

    进程间通信 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的. 进程队列queue 不同于线程queue,进程 ...

  7. (转)Python黑魔法 --- 异步IO( asyncio) 协程

    转自:http://www.jianshu.com/p/b5e347b3a17c?from=timeline Python黑魔法 --- 异步IO( asyncio) 协程 作者 人世间 关注 201 ...

  8. 深入浅析python中的多进程、多线程、协程

    深入浅析python中的多进程.多线程.协程 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源 ...

  9. python基础之进程、线程、协程篇

    一.多任务(多线程) 多线程特点:(1)线程的并发是利用cpu上下文的切换(是并发,不是并行)(2)多线程执行的顺序是无序的(3)多线程共享全局变量(4)线程是继承在进程里的,没有进程就没有线程(5) ...

随机推荐

  1. COM组件转换为.NET元数据2

    上一篇通过命令的方式实现COM组件与.NET元素的转换.这次直接在VS中转换. 以下为步骤:

  2. java的热部署和热加载

    ps:热部署和热加载其实是两个类似但不同的概念,之前理解不深,so,这篇文章重构了下. 一.热部署与热加载 在应用运行的时升级软件,无需重新启动的方式有两种,热部署和热加载. 对于Java应用程序来说 ...

  3. db2 调整连接数的优化

    The Version 9.5 default for the max_coordagents and max_connections parameters will be AUTOMATIC, wi ...

  4. 关于前端框架BootStrap和JQueryUI(以及相应的优秀模板)

    近期两个月因为须要升级公司产品的界面.所以不得不去学习了下原本并不熟悉的前端框架. 这里也是推荐两款BootStrap和JQueryUI. bootstrap使用起始非常easy,首先.须要得到所须要 ...

  5. 最全面的JS表单验证

    两个日期比較 /*  用途:检查開始日期是否小于等于结束日期 输入:  s:字符串 開始日期 格式:2001-5-4 e:字符串 结束日期 格式:2002-5-4 返回:  假设通过開始日期小于等于结 ...

  6. 11g使用非duplicate方式创建物理standby要注意的问题总结

    在上篇博文中,使用了duplicate方式来创建物理standby http://blog.csdn.net/aaron8219/article/details/38434579 今天来说说在11g中 ...

  7. python模块 - re模块使用演示样例

    http://blog.csdn.net/pipisorry/article/details/46619179 re模块匹配规则见:http://blog.csdn.net/pipisorry/art ...

  8. linux系统安全及应用

    小伙伴们让我们一起回顾一下Linux系统安全基础知识吧 1. 系统账号清理 对于公司里刚离职或停职不久的人,处于公司信息安全考虑,给他们的账号给锁定就好了. usermod -L wangqingxi ...

  9. jquery技巧小结

    由于主要还是负责后端,所以前端很多东西都不熟悉,jQuery作为web开发必备技能,有很多知识点,老是记不清楚,所以在这边整理一下. 1.加载页面后执行 $(function(){ //程序段 }) ...

  10. 翻译:MariaDB RENAME TABLE语句

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...