简单谈谈python中的Queue与多进程


Posted in Python onAugust 25, 2016

最近接触一个项目,要在多个虚拟机中运行任务,参考别人之前项目的代码,采用了多进程来处理,于是上网查了查python中的多进程

一、先说说Queue(队列对象)

Queue是python中的标准库,可以直接import 引用,之前学习的时候有听过著名的“先吃先拉”与“后吃先吐”,其实就是这里说的队列,队列的构造的时候可以定义它的容量,别吃撑了,吃多了,就会报错,构造的时候不写或者写个小于1的数则表示无限多

import Queue

q = Queue.Queue(10)

向队列中放值(put)

q.put(‘yang')

q.put(4)

q.put([‘yan','xing'])

在队列中取值get()

默认的队列是先进先出的

>>> q.get()
‘yang'
>>> q.get()
4
>>> q.get()
[‘yan', ‘xing']

当一个队列为空的时候如果再用get取则会堵塞,所以取队列的时候一般是用到

get_nowait()方法,这种方法在向一个空队列取值的时候会抛一个Empty异常

所以更常用的方法是先判断一个队列是否为空,如果不为空则取值

队列中常用的方法

Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.get([block[, timeout]]) 获取队列,timeout等待时间
Queue.get_nowait() 相当Queue.get(False)
非阻塞 Queue.put(item) 写入队列,timeout等待时间
Queue.put_nowait(item) 相当Queue.put(item, False)

二、multiprocessing中使用子进程概念

from multiprocessing import Process

可以通过Process来构造一个子进程

p = Process(target=fun,args=(args))

再通过p.start()来启动子进程

再通过p.join()方法来使得子进程运行结束后再执行父进程

from multiprocessing import Process
import os
 
# 子进程要执行的代码
def run_proc(name):
 print 'Run child process %s (%s)...' % (name, os.getpid())
 
if __name__=='__main__':
 print 'Parent process %s.' % os.getpid()
 p = Process(target=run_proc, args=('test',))
 print 'Process will start.'
 p.start()
 p.join()
 print 'Process end.'

简单谈谈python中的Queue与多进程

三、在multiprocessing中使用pool

如果需要多个子进程时可以考虑使用进程池(pool)来管理

from multiprocessing import Pool

from multiprocessing import Pool
import os, time
 
def long_time_task(name):
 print 'Run task %s (%s)...' % (name, os.getpid())
 start = time.time()
 time.sleep(3)
 end = time.time()
 print 'Task %s runs %0.2f seconds.' % (name, (end - start))
 
if __name__=='__main__':
 print 'Parent process %s.' % os.getpid()
 p = Pool()
 for i in range(5):
  p.apply_async(long_time_task, args=(i,))
 print 'Waiting for all subprocesses done...'
 p.close()
 p.join()
 print 'All subprocesses done.'

pool创建子进程的方法与Process不同,是通过

p.apply_async(func,args=(args))实现,一个池子里能同时运行的任务是取决你电脑的cpu数量,如我的电脑现在是有4个cpu,那会子进程task0,task1,task2,task3可以同时启动,task4则在之前的一个某个进程结束后才开始

简单谈谈python中的Queue与多进程

上面的程序运行后的结果其实是按照上图中1,2,3分开进行的,先打印1,3秒后打印2,再3秒后打印3

代码中的p.close()是关掉进程池子,是不再向里面添加进程了,对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了。

当时也可以是实例pool的时候给它定义一个进程的多少

如果上面的代码中p=Pool(5)那么所有的子进程就可以同时进行

三、多个子进程间的通信

多个子进程间的通信就要采用第一步中说到的Queue,比如有以下的需求,一个子进程向队列中写数据,另外一个进程从队列中取数据,

#coding:gbk

from multiprocessing import Process, Queue
import os, time, random

# 写数据进程执行的代码:
def write(q):
 for value in ['A', 'B', 'C']:
  print 'Put %s to queue...' % value
  q.put(value)
  time.sleep(random.random())

# 读数据进程执行的代码:
def read(q):
 while True:
  if not q.empty():
   value = q.get(True)
   print 'Get %s from queue.' % value
   time.sleep(random.random())
  else:
   break

if __name__=='__main__':
 # 父进程创建Queue,并传给各个子进程:
 q = Queue()
 pw = Process(target=write, args=(q,))
 pr = Process(target=read, args=(q,))
 # 启动子进程pw,写入:
 pw.start() 
 # 等待pw结束:
 pw.join()
 # 启动子进程pr,读取:
 pr.start()
 pr.join()
 # pr进程里是死循环,无法等待其结束,只能强行终止:
 print
 print '所有数据都写入并且读完'

四、关于上面代码的几个有趣的问题

if __name__=='__main__': 
 # 父进程创建Queue,并传给各个子进程:
 q = Queue()
 p = Pool()
 pw = p.apply_async(write,args=(q,)) 
 pr = p.apply_async(read,args=(q,))
 p.close()
 p.join()
 
 print
 print '所有数据都写入并且读完'

如果main函数写成上面的样本,本来我想要的是将会得到一个队列,将其作为参数传入进程池子里的每个子进程,但是却得到

RuntimeError: Queue objects should only be shared between processes through inheritance

的错误,查了下,大意是队列对象不能在父进程与子进程间通信,这个如果想要使用进程池中使用队列则要使用multiprocess的Manager类

if __name__=='__main__':
 manager = multiprocessing.Manager()
 # 父进程创建Queue,并传给各个子进程:
 q = manager.Queue()
 p = Pool()
 pw = p.apply_async(write,args=(q,))
 time.sleep(0.5)
 pr = p.apply_async(read,args=(q,))
 p.close()
 p.join()
 
 print
 print '所有数据都写入并且读完'

这样这个队列对象就可以在父进程与子进程间通信,不用池则不需要Manager,以后再扩展multiprocess中的Manager类吧

关于锁的应用,在不同程序间如果有同时对同一个队列操作的时候,为了避免错误,可以在某个函数操作队列的时候给它加把锁,这样在同一个时间内则只能有一个子进程对队列进行操作,锁也要在manager对象中的锁

#coding:gbk
 
from multiprocessing import Process,Queue,Pool
import multiprocessing
import os, time, random
 
# 写数据进程执行的代码:
def write(q,lock):
 lock.acquire() #加上锁
 for value in ['A', 'B', 'C']:
  print 'Put %s to queue...' % value  
  q.put(value)  
 lock.release() #释放锁 
 
# 读数据进程执行的代码:
def read(q):
 while True:
  if not q.empty():
   value = q.get(False)
   print 'Get %s from queue.' % value
   time.sleep(random.random())
  else:
   break
 
if __name__=='__main__':
 manager = multiprocessing.Manager()
 # 父进程创建Queue,并传给各个子进程:
 q = manager.Queue()
 lock = manager.Lock() #初始化一把锁
 p = Pool()
 pw = p.apply_async(write,args=(q,lock)) 
 pr = p.apply_async(read,args=(q,))
 p.close()
 p.join()
 
 print
 print '所有数据都写入并且读完'
Python 相关文章推荐
python socket网络编程步骤详解(socket套接字使用)
Dec 06 Python
pycharm 使用心得(八)如何调用另一文件中的函数
Jun 06 Python
Python 获取新浪微博的最新公共微博实例分享
Jul 03 Python
浅谈Python单向链表的实现
Dec 24 Python
Python中文分词实现方法(安装pymmseg)
Jun 14 Python
Python中类型检查的详细介绍
Feb 13 Python
python requests post多层字典的方法
Dec 27 Python
python实现从尾到头打印单链表操作示例
Feb 22 Python
python根据完整路径获得盘名/路径名/文件名/文件扩展名的方法
Apr 22 Python
Python计算信息熵实例
Jun 18 Python
Python多线程 Queue 模块常见用法
Jul 04 Python
Python获取江苏疫情实时数据及爬虫分析
Aug 02 Python
利用Python自动监控网站并发送邮件告警的方法
Aug 24 #Python
巧用python和libnmapd,提取Nmap扫描结果
Aug 23 #Python
Python中属性和描述符的正确使用
Aug 23 #Python
Python实现基本线性数据结构
Aug 22 #Python
Python进行数据提取的方法总结
Aug 22 #Python
详解Python实现按任意键继续/退出的功能
Aug 19 #Python
利用Python开发微信支付的注意事项
Aug 19 #Python
You might like
php set_magic_quotes_runtime() 函数过时解决方法
2010/07/08 PHP
利用php+mysql来做一个功能强大的在线计算器
2010/10/12 PHP
php设计模式 Strategy(策略模式)
2011/06/26 PHP
在WordPress的文章编辑器中设置默认内容的方法
2015/12/29 PHP
YII框架http缓存操作示例
2019/04/29 PHP
[原创]静态页面也可以实现预览 列表不同的显示方式
2006/10/14 Javascript
baidu博客的编辑友情链接的新的层窗口!经典~支持【FF】
2007/02/09 Javascript
js 数据类型转换总结笔记
2011/01/17 Javascript
jQuery遍历Form示例代码
2013/09/03 Javascript
浅谈JavaScript中的Math.atan()方法的使用
2015/06/14 Javascript
JS实现三级折叠菜单特效,其它级可自动收缩
2015/08/06 Javascript
JavaScript中通过提示框跳转页面的方法
2016/02/14 Javascript
超实用的javascript时间处理总结
2016/08/16 Javascript
整理一下常见的IE错误
2016/11/18 Javascript
JavaScript使用delete删除数组元素用法示例【数组长度不变】
2017/01/17 Javascript
JavaScript观察者模式(publish/subscribe)原理与实现方法
2017/03/30 Javascript
jQuery简单实现对数组去重及排序操作实例
2017/10/31 jQuery
zTree节点文字过多的处理方法
2017/11/24 Javascript
浅谈微信JS-SDK 微信分享接口开发(介绍版)
2018/08/15 Javascript
基于vue如何发布一个npm包的方法步骤
2019/05/15 Javascript
微信小程序云函数使用mysql数据库过程详解
2019/08/07 Javascript
angular8.5集成TinyMce5的使用和详细配置(推荐)
2020/11/16 Javascript
如何在vue中使用video.js播放m3u8格式的视频
2021/02/01 Vue.js
[01:35:53]完美世界DOTA2联赛PWL S3 Magma vs GXR 第二场 12.13
2020/12/17 DOTA
记录Django开发心得
2014/07/16 Python
Python Collatz序列实现过程解析
2019/10/12 Python
浅谈tensorflow中张量的提取值和赋值
2020/01/19 Python
TensorFlow keras卷积神经网络 添加L2正则化方式
2020/05/22 Python
关于前端上传文件全面基础扫盲贴(入门)
2019/08/01 HTML / CSS
Tory Burch德国官网:美国时尚生活品牌
2018/01/03 全球购物
英国No.1体育用品零售商:SportsDirect.com
2019/10/16 全球购物
医药工作者的求职信范文
2013/09/21 职场文书
业务部主管岗位职责
2014/01/29 职场文书
学校献爱心活动总结
2014/07/08 职场文书
安阳殷墟导游词
2015/02/10 职场文书
2019年“红色之旅”心得体会1000字(3篇)
2019/09/27 职场文书