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的多 ...
随机推荐
- js拷贝实例;
,]]; // var arr2 =arr1.slice(0); // arr1[0] ="z"; // arr1[2][0] = "v"; // consol ...
- vue中eventbus被多次触发(vue中使用eventbus踩过的坑)【bus.$on事件被多次绑定】
问题描述:只要页面没有强制刷新,存在组件切换,bus.$on方法会被多次绑定,造成事件多次触发 触发bus.$on中绑定的方法.png bus.$on多次绑定.png 解决办法:在每次调用方法 ...
- Android控件第5类——ViewAnimator
1.ViewAnimator,继承自FrameLayout ViewAnimator是一个基类,它继承自FrameLayout.它的子类有ViewSwitcher和ViewFlipper:ViewSw ...
- DTD举例一
DTD举例一: <!--动作库约束文件--> <!DOCTYPE actionGroup [ <!ELEMENT actionGroup (action*)> <! ...
- mysql5.7 rpm安装教程
注意版本和此次更新时间 2017-12-03 版本:mysql-5.7.20-1.el6.x86_64 环境:linux6.x 官方下载地址: wget https://dev.mysql.co ...
- BZOJ1915[USACO 2010 Open Gold 1.Cow Hopscotch]——DP+斜率优化
题目描述 奶牛们正在回味童年,玩一个类似跳格子的游戏,在这个游戏里,奶牛们在草地上画了一行N个格子,(3 <=N <= 250,000),编号为1..N.就像任何一个好游戏一样,这样的跳格 ...
- 【BZOJ2671】Calc(莫比乌斯反演)
[BZOJ2671]Calc 题面 BZOJ 给出N,统计满足下面条件的数对(a,b)的个数: 1.\(1\le a\lt b\le N\) 2.\(a+b\)整除\(a*b\) 我竟然粘了题面!!! ...
- AtCoder Grand Contest 011
AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...
- SharePoint 2013 Central Admin 不能打开
当我准备打开CA时发现下面的错误: This operation can be performed only on a computer that is joined to a server farm ...
- Spark 集成开发
WordCount.py # coding:utf-8 from pyspark import SparkContext from pyspark import SparkConf def SetLo ...