简单谈谈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 中整型对象存储的位置
May 16 Python
Python新手入门最容易犯的错误总结
Apr 24 Python
Python开发的实用计算器完整实例
May 10 Python
用十张图详解TensorFlow数据读取机制(附代码)
Feb 06 Python
利用pandas读取中文数据集的方法
Jul 25 Python
解决python3 HTMLTestRunner测试报告中文乱码的问题
Dec 17 Python
Python获取Redis所有Key以及内容的方法
Feb 19 Python
python实现QQ空间自动点赞功能
Apr 09 Python
安装PyInstaller失败问题解决
Dec 14 Python
已安装tensorflow-gpu,但keras无法使用GPU加速的解决
Feb 07 Python
在python tkinter界面中添加按钮的实例
Mar 04 Python
Python中对象的比较操作==和is区别详析
Feb 12 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结合正则批量抓取网页中邮箱地址
2015/05/19 PHP
PHP用户管理中常用接口调用实例及解析(含源码)
2017/03/09 PHP
PHP-X系列教程之内置函数的使用示例
2017/10/16 PHP
无阻塞加载脚本分析[全]
2011/01/20 Javascript
javascript相等运算符与等同运算符详细介绍
2013/11/09 Javascript
javascript loadScript异步加载脚本示例讲解
2013/11/14 Javascript
JavaScript学习笔记之基础语法
2015/01/22 Javascript
JavaScript生成SQL查询表单的方法
2015/08/13 Javascript
jQuery实现将div中滚动条滚动到指定位置的方法
2016/08/10 Javascript
Angular表单验证实例详解
2016/10/20 Javascript
nodejs个人博客开发第四步 数据模型
2017/04/12 NodeJs
Angular.JS中select下拉框设置value的方法
2017/06/20 Javascript
Js利用console计算代码运行时间的方法示例
2017/09/24 Javascript
详解实现一个通用的“划词高亮”在线笔记功能
2019/04/23 Javascript
nuxt框架中对vuex进行模块化设置的实现方法
2019/09/06 Javascript
js计时事件实现圆形时钟
2020/03/25 Javascript
vue中使用rem布局代码详解
2019/10/30 Javascript
[02:48]DOTA2超级联赛专访海涛:你们的选择没有错
2013/06/07 DOTA
使用Python的判断语句模拟三目运算
2015/04/24 Python
Django ORM框架的定时任务如何使用详解
2017/10/19 Python
Matplotlib中文乱码的3种解决方案
2018/11/15 Python
python列表推导式入门学习解析
2019/12/02 Python
python几种常用功能实现代码实例
2019/12/25 Python
用Python生成HTML表格的方法示例
2020/03/06 Python
Python中使用socks5设置全局代理的方法示例
2020/04/15 Python
Python requests.post方法中data与json参数区别详解
2020/04/30 Python
python利用蒙版抠图(使用PIL.Image和cv2)输出透明背景图
2020/08/04 Python
CSS3 box-sizing属性详解
2016/11/15 HTML / CSS
英超联赛的首选足球:Mitre足球
2019/05/06 全球购物
彪马土耳其官网:PUMA土耳其
2019/07/14 全球购物
网络优化专员求职信
2014/05/04 职场文书
2014年六一儿童节演讲稿
2014/05/23 职场文书
2014年数学教师工作总结
2014/12/03 职场文书
2015年领班工作总结
2015/04/29 职场文书
给老婆的保证书怎么写
2015/05/08 职场文书
生鲜超市—未来中国最具有潜力零售业态
2019/08/02 职场文书