python多进程那点事儿【multiprocessing库】
前言:项目中有个需求需要对产品的日志处理,按照产品中日志的某些字段,对日志进行再次划分。比如产品的日志中含有字段id,tag=1,现在需要把tag是基数的放到一个文件中,tag是偶数的放入一个文件中。这就涉及到多个文件的读写操作,一个文件一个文件读取写入那时间太久了,公司配备的单机,跑了半个多小时,光标还是一直在闪闪闪【你懂得】。没办法了,还是用多进程跑吧。这就得对python中的多进程从新回顾一遍了。
Q1:为什么不用多线程呢?
A1:这个就需要了解python多线程的实现原理了,通过在其解释器层面施加一个全局锁来保证同一时刻只有一个线程可以拥有锁,执行相应的python字节码。所以虽然冠名是是多线程,但是实质上还是只有一个线程在运行。有时候多线程可能会让程序得不到提高反而降低,因为线程之间需要竞争资源。所以很多人也说,如果想真正的同一时刻执行多个任务的话,就需要使用多进程。
1.使用multiprocessing.Process
multiprocessing.Process最常见的使用就是:
p = multiprocessing.Process(target = 多线程执行函数名, args = 函数参数元组形式)
p.start()
p.join()
注意使用多进程时候一定要使用join对子进程的状态进行收集,否则在程序运行过程中会出现僵尸进程,对系统性能造成影响。
当然,上面这只有一个进程,你在写的时候可能很顺手就写了
for x in range(10):
p = multiprocessing.Process(target = 多线程执行函数名, args = 函数参数元组形式)
p.start()
p.join()
然后就发现,这个进程貌似是顺序执行的。。。好像没有并发,原因就出现在join的位置上,仔细查看手册,你会发现在join函数下方有一行说明:
Block the calling thread until the process whose join() method is called terminates or until the optional timeout occurs.
意思就是主线程会在join的地方一直等子进程结束。。那么我们多个进程并发执行就要这样写了:
p_list = []
for x in range(10):
p = multiprocessing.Process(target = 多线程执行函数名, args = 函数参数元组形式)
p.start()
p_list.append(p) for p in p_list:
p.join()
感觉这样写的代码一点都不优雅,而且以后拓展也很不方便,子进程的数目会随着任务数目的增加而增加,进程得不到重复的利用。
2.使用multiprocessing.Pool
进程池就是上述不方便的完美解决,其一般用法如下:
pool = multiprocessing.Pool(processes=进程数目)
for x in xrange(任务数目):
pool.apply_async(函数名, 函数参数元组形式)
pool.close() # close函数表明不会再往进程池中加入新任务,一定要在join方法调用之前调用。
pool.join()
上述代码开启了含有一定数目的进程池,只需要往进程池中加入新任务即可,当进程池中已满,其他的任务就等待,直到有任务结束。
注意:除了pool.apply_async方法,还有一个pool.apply方法,只不过pool.apply方法是阻塞的。
还可以使用进程池方法来关注进程执行的结果,pool.apply_asyn函数即返回函数的执行结果,使用get()方法即可得到。
3.多进程共享数据
多个进程之间共享数据也有很多种方法:
1)共享变量
只能使用Value和Array方法:
multiprocessing.Value(typecode_or_type, *args[, lock])
multiprocessing.Array(typecode_or_type, size_or_initializer, *, lock=True)
关于lock的一段说明:
Return a process-safe wrapper object for a ctypes object which uses lock to synchronize access. If lock is None (the default) then a multiprocessing.RLock object is created automatically.
共享变量只能是一个变量,或者是线性的一组变量,类型也是从typecode_or_type衍生而来的,具体的用法和说明手册上已经讲解的很清楚了。附上手册上的一段代码如下:
from multiprocessing import Process, Lock
from multiprocessing.sharedctypes import Value, Array
from ctypes import Structure, c_double class Point(Structure):
_fields_ = [('x', c_double), ('y', c_double)] def modify(n, x, s, A):
n.value **= 2
x.value **= 2
s.value = s.value.upper()
for a in A:
a.x **= 2
a.y **= 2 if __name__ == '__main__':
lock = Lock() n = Value('i', 7)
x = Value(c_double, 1.0/3.0, lock=False)
s = Array('c', 'hello world', lock=lock)
A = Array(Point, [(1.875,-6.25), (-5.75,2.0), (2.375,9.5)], lock=lock) p = Process(target=modify, args=(n, x, s, A))
p.start()
p.join() print n.value
print x.value
print s.value
print [(a.x, a.y) for a in A]
结果:
49
0.1111111111111111
HELLO WORLD
[(3.515625, 39.0625), (33.0625, 4.0), (5.640625, 90.25)]
2)Manager
使用Manager方法时,共享变量的类型会多一些,例如list,dict,Event,Lock,Array,Value...使用Manager方法时需要注意,在操作共享对象时候,除了赋值操作,其他的方法都作用在共享对象的拷贝上,并不会对共享对象生效。例如:
d = Manager().dict()
d[0] = []
d[0].append(0) # append方法作用在代理对象上,并不对原始对象生效
print d
输出:{0: []}
而同样意思的一段代码:
d = Manager().dict()
l = []
l.append(0)
d[0] = l # 直接赋值操作,影响原始共享对象
print d
输出:{0: [0]}
3)Queue
队列,顾名思义,就是一组数据,使用put来往队列中存入数据,使用get方法获取数据,当队列满了继续put和队列空了继续get时候会抛出相对应的异常。可以多个进程之间传递数据。
4)Pipe
Pipe方法返回(conn1, conn2)代表一个管道的两个端,对应两个进程。还可以通过duplex来设定管道是全双工(duplex=True)还是半双工(duplex=False)工作。send和recv方法分别是发送和接受消息的方法,如果没有消息可接收,recv方法会一直阻塞。如果管道已经被关闭,那么recv方法会抛出EOFError。
4.多进程同步互斥
1)Lock和Semaphore
这两个就不多讲了,学过操作系统的都知道。Lock限定同一时间仅一个进程访问共享变量,Semaphore则可以限定多个进程同时访问共享变量。
2)Event
使用set和is_set判断事件是否已经发生,决定下一步要执行的动作。
python多进程那点事儿【multiprocessing库】的更多相关文章
- Python: 多进程的分布式进程multiprocessing.managers
multiprocessing.managers 在Thread和Process中,应当优选Process,因为Process更稳定,而且,Process可以分布到多台机器上,而Thread最多只能分 ...
- Python 多进程异常处理
前言 最近项目用到了Python作为网站的前端,使用的框架是基于线程池的Cherrypy,但是前端依然有一些比较‘重’的模块.由于python的多线程无法很好的利用多核的性质,所以觉得把这些比较‘重’ ...
- Python多进程库multiprocessing中进程池Pool类的使用[转]
from:http://blog.csdn.net/jinping_shi/article/details/52433867 Python多进程库multiprocessing中进程池Pool类的使用 ...
- Python多进程库multiprocessing创建进程以及进程池Pool类的使用
问题起因最近要将一个文本分割成好几个topic,每个topic设计一个regressor,各regressor是相互独立的,最后汇总所有topic的regressor得到总得预测结果.没错!类似bag ...
- Python多进程multiprocessing使用示例
mutilprocess简介 像线程一样管理进程,这个是mutilprocess的核心,他与threading很是相像,对多核CPU的利用率会比threading好的多. import multipr ...
- Python多进程并发(multiprocessing)用法实例详解
http://www.jb51.net/article/67116.htm 本文实例讲述了Python多进程并发(multiprocessing)用法.分享给大家供大家参考.具体分析如下: 由于Pyt ...
- Python 多进程multiprocessing
一.python多线程其实在底层来说只是单线程,因此python多线程也称为假线程,之所以用多线程的意义是因为线程不停的切换这样比串行还是要快很多.python多线程中只要涉及到io或者sleep就会 ...
- Python多进程池 multiprocessing Pool
1. 背景 由于需要写python程序, 定时.大量发送htttp请求,并对结果进行处理. 参考其他代码有进程池,记录一下. 2. 多进程 vs 多线程 c++程序中,单个模块通常是单进程,会启动几十 ...
- python多进程-----multiprocessing包
multiprocessing并非是python的一个模块,而是python中多进程管理的一个包,在学习的时候可以与threading这个模块作类比,正如我们在上一篇转载的文章中所提,python的多 ...
随机推荐
- [读书笔记]Linux命令行与shell编程读书笔记04 安装软件,编辑器注意事项
1. debian以及redhat两种主流的linux发行版用的包管理工具 debian的包管理工具是 dpkg 再现安装的是 apt apt的工具主要有 apt-get apt-cache apti ...
- SLAM中的变换(旋转与位移)表示方法
1.旋转矩阵 注:旋转矩阵标题下涉及到的SLAM均不包含位移. 根据同一点P在不同坐标系下e(e1,e2,e3)e'(e1',e2',e3')的坐标a(a1,a2,a3)a'(a1',a2',a3') ...
- appium框架感悟
个人觉得 所谓框架 最终结果就是对存放的元素进行处理 从底层获取数据 往上层传输数据过程中 对其一步一步的封装 由繁到简 再由繁至简
- 学习记录特别篇之sql,类的继承
思路: 应用场景: 1.将父类当做一个基础类 大家都去继承该方法,以便少些代码 2.继承父类的方法 同时可以重写该方法时候调用父类原先的方法 实现一石二鸟的效果 即 既增加原先的功能 又新增新的功能 ...
- 设计模式【PHP案例】
内容来源: 波客 菜鸟教程 策略模式 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改.这种类型的设计模式属于行为型模式. 在策略模式中,我们创建表示各种策略的对 ...
- ajax 调用 java webapi 多个参数(二)
第一种方法:http://blog.csdn.net/hanjun0612/article/details/74436273 附上另一种解决方法. 这个方法主要针对 嵌套模型(模型中含有模型)的ap ...
- servlet表单中get和post方法的区别
Form中的get和post方法,在数据传输过程中分别对应了HTTP协议中的GET和POST方法.二者主要区别如下: 1.Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据. 2.Ge ...
- 任意目录下启动tomcat
DOS中启动tomcat 1.将tomcat的bin目录添加到Path变量中 2.添加catalina_home变量 3.命令行输入catalina run ojbk
- git pull报“unable to update local ref”解决方案
使用git pull拉取代码的时候,无法拉取最新代码,报"unable to update local ref"错误. 除了重新clone一份代码外,还可以使用如下解决方案: 1. ...
- BZOJ 4671 异或图 | 线性基 容斥 DFS
题面 Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中 ...