python多进程并发进程池Pool
简介:
python中的多进程主要使用到 multiprocessing 这个库。低版本python这个库在使用 multiprocessing.Manager().Queue时会出问题,建议大家升级到高版本python。
一、多进程使用
1、linux下可使用 fork 函数
#!/bin/env python
import os print 'Process (%s) start...' % os.getpid()
pid = os.fork()
if pid==0:
print 'I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())
os._exit(1)
else:
print 'I (%s) just created a child process (%s).' % (os.getpid(), pid)
输出
Process (22246) start...
I (22246) just created a child process (22247).
I am child process (22247) and my parent is 22246.
2、使用 multiprocessing
#!/bin/env python
from multiprocessing import Process
import os
import time def run_proc(name):
time.sleep(3)
print 'Run child process %s (%s)...' % (name, os.getpid()) if __name__=='__main__':
print 'Parent process %s.' % os.getpid()
processes = list()
for i in range(5):
p = Process(target=run_proc, args=('test',))
print 'Process will start.'
p.start()
processes.append(p) for p in processes:
p.join()
print 'Process end.'
输出
Parent process 38140.
Process will start.
Process will start.
Process will start.
Process will start.
Process will start.
Run child process test (38141)...
Run child process test (38142)...
Run child process test (38143)...
Run child process test (38145)...
Run child process test (38144)...
Process end. real 0m3.028s
user 0m0.021s
sys 0m0.004s
二、进程池Pool
Pool类相和关方法介绍:
Pool类可以提供指定数量的进程供用户调用,当有新的请求提交到Pool中时,如果池还没有满,就会创建一个新的进程来执行请求。如果池满,请求就会告知先等待,直到池中有进程结束,才会创建新的进程来执行这些请求。
下面介绍一下multiprocessing 模块下的Pool类下的几个方法:
apply()
函数原型:apply(func[, args=()[, kwds={}]])
该函数用于传递不定参数,同python中的apply函数一致,主进程会被阻塞直到函数执行结束(不建议使用,并且3.x以后不在出现)。
apply_async
函数原型:apply_async(func[, args=()[, kwds={}[, callback=None]]])
与apply用法一致,但它是非阻塞的且支持结果返回后进行回调。
map()
函数原型:map(func, iterable[, chunksize=None])
Pool类中的map方法,与内置的map函数用法行为基本一致,它会使进程阻塞直到结果返回。
注意:虽然第二个参数是一个迭代器,但在实际使用中,必须在整个队列都就绪后,程序才会运行子进程。
map_async()
函数原型:map_async(func, iterable[, chunksize[, callback]])
与map用法一致,但是它是非阻塞的。其有关事项见apply_async。
close()
关闭进程池(pool),使其不在接受新的任务。
terminal()
结束工作进程,不在处理未处理的任务。
join()
主进程阻塞等待子进程的退出, join方法要在close或terminate之后使用。
1、使用 multiprocessing.Pool 非阻塞
#!/bin/env python import multiprocessing
import time def func(msg):
print "msg:", msg
time.sleep(3)
print "end" if __name__ == "__main__":
pool = multiprocessing.Pool(processes = 3)
for i in xrange(3):
msg = "hello %d" %(i)
pool.apply_async(func, (msg, )) print "Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~"
pool.close()
pool.join() # behind close() or terminate()
print "Sub-process(es) done.
运行结果
Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~
msg: hello 0
msg: hello 1
msg: hello 2
end
end
end
Sub-process(es) done. real 0m3.493s
user 0m0.056s
sys 0m0.022s
2、使用 multiprocessing.Pool 阻塞版本
下面我们看一个简单的multiprocessing.Pool类的实例:
#!/bin/env python import multiprocessing
import time def func(msg):
print "msg:", msg
time.sleep(3)
print "end" if __name__ == "__main__":
pool = multiprocessing.Pool(processes = 3)
for i in xrange(3):
msg = "hello %d" %(i)
pool.apply(func, (msg, )) print "Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~"
pool.close()
pool.join() # behind close() or terminate()
print "Sub-process(es) done."
运行结果
msg: hello 0
end
msg: hello 1
end
msg: hello 2
end
Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~
Sub-process(es) done. real 0m9.061s
user 0m0.036s
sys 0m0.019s
区别主要是 apply_async和 apply函数,前者是非阻塞的,后者是阻塞。可以看出运行时间相差的倍数正是进程池数量
3、使用 multiprocessing.Pool 并关注结果
import multiprocessing
import time def func(msg):
print "msg:", msg
time.sleep(3)
print "end"
return "done" + msg if __name__ == "__main__":
pool = multiprocessing.Pool(processes=4)
result = []
for i in xrange(3):
msg = "hello %d" %(i)
result.append(pool.apply_async(func, (msg, )))
pool.close()
pool.join()
for res in result:
print ":::", res.get()
print "Sub-process(es) done."
运行结果
msg: hello 0
msg: hello 1
msg: hello 2
end
end
end
::: donehello 0
::: donehello 1
::: donehello 2
Sub-process(es) done. real 0m3.526s
user 0m0.054s
sys 0m0.024s
4、在类中使用 multiprocessing.Pool
类中使用进程池会一般会出现错误
PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed
这个提示是因为 multiprocessing.Pool中使用了Queue通信,所有进入队列的数据必须可序列化(picklable),包括自定义类实例等。如下:
#!/bin/env python import multiprocessing class SomeClass(object):
def __init__(self):
pass def f(self, x):
return x*x def go(self):
pool = multiprocessing.Pool(processes=4)
#result = pool.apply_async(self.f, [10])
#print result.get(timeout=1)
print pool.map(self.f, range(10)) SomeClass().go()
运行提示
Traceback (most recent call last):
File "4.py", line 18, in <module>
SomeClass().go()
File "4.py", line 16, in go
print pool.map(self.f, range(10))
File "/usr/local/lib/python2.7/multiprocessing/pool.py", line 251, in map
return self.map_async(func, iterable, chunksize).get()
File "/usr/local/lib/python2.7/multiprocessing/pool.py", line 567, in get
raise self._value
cPickle.PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed
解决如下:(1)
#!/bin/env python
import multiprocessing def func(x):
return x*x class SomeClass(object):
def __init__(self,func):
self.f = func def go(self):
pool = multiprocessing.Pool(processes=4)
#result = pool.apply_async(self.f, [10])
#print result.get(timeout=1)
print pool.map(self.f, range(10)) SomeClass(func).go()
输出结果:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
(2)一般情况下我们如果在类中写好了处理逻辑,想要尽可能减少代码变动则可以使用下面方法
#!/bin/env python import multiprocessing class SomeClass(object):
def __init__(self):
pass def f(self, x):
return x*x def go(self):
result = list()
pool = multiprocessing.Pool(processes=4)
for i in range(10):
result.append(pool.apply_async(func, [self, i]))
pool.close()
pool.join()
for res in result:
print res.get(timeout=1) def func(client, x):
return client.f(x) SomeClass().go()
输出结果:
0
1
4
9
16
25
36
49
64
81
使用(2)的解决方法需要注意,如果SomeClass实例中有包含任何不可序列化的数据则会一直报错,一般是到res.get()报错,这时候你就要重新查看代码是否有不可序列化的变量了。如果有的话可以更改成全局变量解决。
三、多进程中使用线程池
有一种情景下需要使用到多进程和多线程:在CPU密集型的情况下一个ip的处理速度是0.04秒前后,单线程运行的时间大概是3m32s,单个CPU使用率100%;使用进程池(size=10)时间大概是6m50s,其中只有1个进程的CPU使用率达到90%,其他均是在30%左右;使用线程池(size=10)时间大概是4m39s,单个CPU使用率100%
可以看出使用多进程在这时候并不占优势,反而更慢。因为进程间的切换消耗了大部分资源和时间,而一个ip只需要0.04秒。而使用线程池由于只能利用单核CPU,则再怎么加大线程数量都没法提升速度,所以这时候应该使用多进程加多线程结合。
def run(self):
self.getData()
ipNums = len(self.ipInfo)
step = ipNums / multiprocessing.cpu_count()
ipList = list()
i = 0
j = 1
processList = list()
for ip in self.ipInfo:
ipList.append(ip)
i += 1
if i == step * j or i == ipNums:
j += 1
def innerRun():
wm = Pool.ThreadPool(CONF.POOL_SIZE)
for myIp in ipList:
wm.addJob(self.handleOne, myIp)
wm.waitForComplete()
process = multiprocessing.Process(target=innerRun)
process.start()
processList.append(process)
ipList = list()
for process in processList:
process.join()
机器有8个CPU,则使用8个进程加线程池,速度提升到35s,8个CPU的利用率均在50%左右,机器平均CPU75%左右。
四、多进程间通信
个人使用的比较多的是队列和共享内存。需要注意的是队列中Queue.Queue是线程安全的,但并不是进程安全,所以多进程一般使用线程、进程安全的multiprocessing.Queue(),而使用这个Queue如果数据量太大会导致进程莫名卡住(绝壁大坑来的),需要不断地消费。
The Queue class is a near clone of Queue.Queue. For example:
from multiprocessing import Process, Queue def f(q):
q.put([42, None, 'hello']) if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print q.get() # prints "[42, None, 'hello']"
p.join()
Queues are thread and process safe.
测试卡住的程序如下:
#!/bin/env python
from multiprocessing import Process, Queue class A(object):
def __init__(self):
pass
def r(self):
def f(q):
import time
time.sleep(1)
s = 2000 * 'ss' # 不卡不卡不卡
# s = 20000 * 'ss' # 卡住卡住卡住
q.put(['hello', s])
print "q.put(['hello', s])"
q = Queue(maxsize=0)
pL = list()
for i in range(10):
p = Process(target=f, args=(q,))
p.start()
pL.append(p)
for p in pL:
p.join()
print len(q.get()) if __name__ == '__main__':
A().r()
python多进程并发进程池Pool的更多相关文章
- day12学python 多进程+进程池
多进程+进程池 多进程(不同进程不可直接访问数据) 引入(多进程套线程) 多进程 需导入multiprocessing模块 模板示例1 import threading,time,multiproce ...
- python 使用进程池Pool进行并发编程
进程池Pool 当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到mu ...
- Python多进程-进程池
进程池可以减轻多进程对CPU的负担 把一个进程序列放入进程池,使用的时候,就会在进程池中取进程如果进程池中没有进程了,脚本就会等待,直到进程池中有可用进程 进程池生成的子线程,不能直接运行,要放入进程 ...
- Python 多进程进程池Queue进程通信
from multiprocessing import Pool,Manager import time def hanshu(queue,a): n = 1 while n<50: # pri ...
- Python多进程池 multiprocessing Pool
1. 背景 由于需要写python程序, 定时.大量发送htttp请求,并对结果进行处理. 参考其他代码有进程池,记录一下. 2. 多进程 vs 多线程 c++程序中,单个模块通常是单进程,会启动几十 ...
- Python多进程库multiprocessing中进程池Pool类的使用[转]
from:http://blog.csdn.net/jinping_shi/article/details/52433867 Python多进程库multiprocessing中进程池Pool类的使用 ...
- python学习笔记——multiprocessing 多进程组件 进程池Pool
1 进程池Pool基本概述 在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量时间,如果操作的对象数目不大时,还可以直接适用Process类动态生成 ...
- Python多进程库multiprocessing创建进程以及进程池Pool类的使用
问题起因最近要将一个文本分割成好几个topic,每个topic设计一个regressor,各regressor是相互独立的,最后汇总所有topic的regressor得到总得预测结果.没错!类似bag ...
- [转]Python多进程并发操作中进程池Pool的应用
Pool类 在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量的时间.如果操作的对象数目不大时,还可以直接使用Process类动态的生成多个进程,十 ...
随机推荐
- 树莓派2安装Xware实现迅雷远程下载
首先,远程功能很实用,尤其是基于迅雷的,现在国内的下载基本上迅雷只手遮天,别的工具友好程度不理想,这是对于我这种小白来说. 首先,我的树莓派系统不是原生的,我烧写的是ubuntu16,没有桌面,没有多 ...
- Java中的Serializable接口和transient关键字
Java中的Serializable接口和transient关键字 Table of Contents 1. 向memcached中放数据时遇到NotSerializableException异常 2 ...
- 获取url的参数值
var url=location.search; //获取url中从?开始的所有字符 var theRequest=new Object();//定义一个对象来存放url中的参数 if( url.i ...
- 织梦dedecms后台登陆密码充值工具
下载后解压,根据自己语言版本,把文件radminpass.php放入网站根目录下执行即可 点击下载:织梦dedecms后台登陆密码充值工具
- CSS font-family 字体名称一览表
windows常见内置中文字体 字体中文名 字体英文名 宋体 SimSun(浏览器默认) 黑体 SimHei 微软雅 ...
- java 通过文件后缀名查找文件
最近开发项目的时候需要过滤出一些指定的文件,所以有了以下的一些代码: /** **该类主要是过滤得到指定后缀名的文件 **/ public class DataFileFilter implement ...
- JavaScript中三种字符串连接方式及其性能比较
参考地址: https://www.cnblogs.com/programs/p/5554742.html 工作中经常会碰到要把2个或多个字符串连接成一个字符串的问题,在JS中处理这类问题一般有三种方 ...
- windows下安装pm2
安装pm2 npm install pm2 -g 添加系统环境变量 PM2_HOME=C:\Users\PCONE\.pm2 打开新的cmd命令行窗口,执行以下命令来安装服务 pm2-service- ...
- 使用com.sun.imageio.plugins.png.PNGMetadata读取图片的元数据
所谓图片元数据,就是除了我们肉眼看到的图片内容外,隐藏在这些内容背后的一些技术数据. 本文介绍如何使用Java代码将一张图片的隐藏信息读取出来. 首先不需要下载任何额外的Java库,用JDK自带的库就 ...
- UVA 1615 Highway 高速公路 (区间选点)
题意:在一条线段上选出尽量少的点,使得和所有给出的n个点距离不超过D. 分别计算出每个点在线段的满足条件的区间,然后就转化成了区间选点的问题了,按照右端点排序,相同时按照左端点排序,按照之前的排序一定 ...