我正在处理程序中的内存泄漏问题。我发现它与多重处理有关,因此我提出了以下实验。
在实验中,函数f生成一个列表和一个元组,我将检查从函数返回后id是否保持不变。
程序返回值最有效的方法是返回引用,以防止为相同的对象分配内存。当SYNC = True时,结果显示来自内部的ID等于从外部接收的ID。
但是,当SYNC = False并且多处理程序加入该程序时,内部的ID将不再等于外部的ID。这表明程序已经创建了对象的额外副本。
这实际上引起了2个问题:
1.复制对象时浪费内存和计算能力
2.保留在池中的副本不会被垃圾收集(通过其他实验发现)
有人能告诉我python处理此问题的机制吗?在引入多处理后如何避免我的程序成为内存吞噬者?
from multiprocessing import Pool
SYNC = False
def f(start):
l = [i for i in range(start, start+100)] # generate a list from start to start-1
t = tuple(i for i in range(start, start+100)) # generate a list from start to start-1
print('inner: {}'.format(id(l)))
print('inner: {}'.format(id(t)))
return l, t
def iterate(it):
for l, t in it:
print('outer: {}'.format(id(l)))
print('outer: {}'.format(id(t)))
pool = Pool(4)
inputs = [i for i in range(4)]
gen_sync = (f(start) for start in inputs)
gen_async = pool.imap(f, inputs, chunksize=4)
if SYNC:
print('start testing sync')
iterate(gen_sync)
else:
print('start testing async')
iterate(gen_async)
SYNC = True
开始测试同步
内部:139905123267144
内部:23185048
外部:139905123267144
外部:23185048
内部:139905123249544
内部:23186776
外部:139905123249544
外部:23186776
内部:139905123267144
内部:23187640
外部:139905123267144
外部:23187640
内部:139905123249544
内部:23185912
外部:139905123249544
外部:23185912
内部:139905142421000
内部:23180456
内部:139905123267144
内部:23182184
内部:139905123249544
内部:23183912
内部:139905123249800
内部:23185640
SYNC = False
开始测试异步
内部:139699492382216
内部:38987640
内部:139699490987656
内部:38989368
内部:139699490985992
内部:38991096
内部:139699490986120
内部:38992824
外部:139699490985992
外部:139699180021064
外部:139699490986120
外部:139699180022888
外部:139699473207560
外部:139699180024712
外部:139699473207880
外部:139699180026536
答案 0 :(得分:1)
我认为您不了解多处理的工作原理。 multiprocessing
启动新的python
进程以运行您的代码。每个进程都有自己的内存空间。当您将inputs
传递给映射时,每个进程都会在其自己的内存空间中获取数据的副本。请参阅有关此问题的答案:Python multiprocessing and a shared counter
如果您确实想要数据的单个副本,则应使用Shared Memory
。
警告:使用起来很麻烦。
https://docs.python.org/dev/library/multiprocessing.shared_memory.html
这是文档中的一个示例:
>>> with SharedMemoryManager() as smm:
... sl = smm.ShareableList(range(2000))
... # Divide the work among two processes, storing partial results in sl
... p1 = Process(target=do_work, args=(sl, 0, 1000))
... p2 = Process(target=do_work, args=(sl, 1000, 2000))
... p1.start()
... p2.start() # A multiprocessing.Pool might be more efficient
... p1.join()
... p2.join() # Wait for all work to complete in both processes
... total_result = sum(sl) # Consolidate the partial results now in sl