当前位置:首页 > 公司荣誉 >

[python]多进程中的内存复制

发布时间:2017-09-12 15:44:54 作者:陕西誉丰源物资有限公司

[python]多进程中的内存复制

比较好奇python对于多进程中copy on write机制的实际使用情况。目前从实验结果来看,python 使用multiprocessing来创建多进程时,无论数据是否不会被更改,子进程都会复制父进程的状态(内存空间数据等)。所以如果主进程耗的资源较多时,站群系统,不小心就会造成不必要的大量的内存复制,从而可能导致内存爆满的情况。


示例
举个例子,假设主进程读取了一个大文件对象的所有行,然后通过multiprocessing创建工作进程,并循环地将每一行数据交给工作进程来处理:
[python]
def parse_lines(args):
#working
...

def main_logic():
f = open(filename , 'r')
<SPAN style="COLOR: #cc0000"> lines = f.readlines()</SPAN>
f.close()

pool = multiprocessing.Pool(processes==4)
<SPAN style="COLOR: #cc0000">rel = pool.map(parse_lines , itertools.izip(lines , itertools.repeat(second_args)) , int(len(lines)/4))</SPAN>
pool.close()
pool.join()

def parse_lines(args):
#working
...

def main_logic():
f = open(filename , 'r')
lines = f.readlines()
f.close()

pool = multiprocessing.Pool(processes==4)
rel = pool.map(parse_lines , itertools.izip(lines , itertools.repeat(second_args)) , int(len(lines)/4))
pool.close()
pool.join()


以下是top及ps结果:

(四个子进程)


(父进程及四个子进程)

由上两张图可以看出父进程及子进程都各自占用了1.4G左右的内存空间。而大部分内存空间存储的是读数据lines,所以这样的内存开销太浪费。


优化计划

计划1:通过内存共享来减少内存的开销。

计划2: 主进程不再读取文件对象,交给每个工作进程去读取文件中的相应部分。

改进代码:


[python]
def line_count(file_name):
count = -1 #让空文件的行号显示0
for count,line in enumerate(open(file_name)): pass
#enumerate格式化成了元组,count就是行号,因为从0开始要+1
return count+1

def parse_lines(args):
f = open(args[0] , 'r')
<SPAN style="COLOR: #cc0000">lines = f.readlines()[args[1]:args[2]] #read some lines</SPAN>
f.close()
#working

def main_logic(filename,process_num):
line_count = line_count(filename)
avg_len = int(line_count/process_num)
left_cnt = line_count%process_num;

pool = multiprocessing.Pool(processes=process_num)
for i in xrange(0,process_num):
ext_cnt = (i>=process_num-1 and [left_cnt] or [0])[0]
st_line = i*avg_len
<SPAN style="COLOR: #cc0000">pool.apply_async(parse_lines, ((filename, st_line, st_line+avg_len+ext_cnt),)) #指定进程读某几行数据</SPAN>
pool.close()
pool.join()

def line_count(file_name):
count = -1 #让空文件的行号显示0
for count,line in enumerate(open(file_name)): pass
#enumerate格式化成了元组,count就是行号,因为从0开始要+1
return count+1

def parse_lines(args):
f = open(args[0] , 'r')
lines = f.readlines()[args[1]:args[2]] #read some lines
f.close()
#working

def main_logic(filename,process_num):
line_count = line_count(filename)
avg_len = int(line_count/process_num)
left_cnt = line_count%process_num;

pool = multiprocessing.Pool(processes=process_num)
for i in xrange(0,process_num):
ext_cnt = (i>=process_num-1 and [left_cnt] or [0])[0]
st_line = i*avg_len
pool.apply_async(parse_lines, ((filename, st_line, st_line+avg_len+ext_cnt),)) #指定进程读某几行数据
pool.close()
pool.join()
再次用top或者ps来查看进程的内存使用情况:

(四个子进程)


(父进程及四个子进程)

小结

对比两次的内存使用情况,改进代码后父进程及子进程所占用的内存明显减少;所有内存占用相当于原来的一半,这就是减少内存复制的效果。

实验暂时先进行到此,站群,关于内存使用这方面还有不少优化方法和空间,稍后继续研究。

企业建站2800元起,携手武汉肥猫科技,做一个有见地的颜值派!更多优惠请戳:孝感网站建设 http://xiaogan.45qun.com

  • 上一篇:QQ空间给移动社区产品的4大启示
  • 下一篇:最后一页