如果我不触摸它,为什么多处理复制我的数据?

时间:2015-06-21 10:45:40

标签: python multithreading python-3.x multiprocessing

我正在追踪一个内存不足的bug,并且惊恐地发现python的多处理似乎复制了大型数组,即使我无意使用它们。

为什么python(在Linux上)这样做,我认为copy-on-write会保护我免受任何额外的复制?我想,无论何时我引用该对象,都会调用某种陷阱,然后才会复制。

对于任意数据类型来说,解决此问题的正确方法是否正确,例如使用{1}}的30千兆字节自定义词典?有没有办法构建Python,以便它没有这个废话?

Monitor

运行:

import numpy as np
import psutil
from multiprocessing import Process
mem=psutil.virtual_memory()
large_amount=int(0.75*mem.available)

def florp():
    print("florp")

def bigdata():
    return np.ones(large_amount,dtype=np.int8)

if __name__=='__main__':
    foo=bigdata()#Allocated 0.75 of the ram, no problems
    p=Process(target=florp)
    p.start()#Out of memory because bigdata is copied? 
    print("Wow")
    p.join()

2 个答案:

答案 0 :(得分:2)

我希望这种行为 - 当您将代码传递给Python进行编译时,任何未在函数或对象后面保护的内容都会立即被exec用于评估。

在您的情况下,必须评估bigdata=np.ones(large_amount,dtype=np.int8) - 除非您的实际代码具有不同的行为,florp()未被调用与它无关。

要看一个直接的例子:

>>> f = 0/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
>>> def f():
...     return 0/0
...
>>>

要将此代码应用于您的代码,请将bigdata=np.ones(large_amount,dtype=np.int8)置于函数后面并根据需要调用它,否则,Python会尝试在运行时将该变量提供给您。

如果bigdata没有变化,您可以编写一个函数来获取或设置一个在过程持续时间内保留的对象。

编辑:咖啡刚开始工作。当您创建一个新进程时,Python需要将所有对象复制到该新进程中以进行访问。您可以通过使用线程或允许您在shared memory maps或共享ctypes

等流程之间共享内存的机制来避免这种情况。

答案 1 :(得分:0)

问题在于,默认情况下Linux检查最坏情况下的内存使用情况,这确实会超过内存容量。即使python语言没有暴露变量也是如此。您需要关闭系统范围内的“overcommit”,以实现预期的COW行为。

sysctl `vm.overcommit_memory=2'

请参阅https://www.kernel.org/doc/Documentation/vm/overcommit-accounting