代码之家  ›  专栏  ›  技术社区  ›  Luc Blassel

oserror:[errno 12]使用python多处理池时无法分配内存

  •  0
  • Luc Blassel  · 技术社区  · 6 年前

    我正在尝试使用python将一个函数并行应用于5个交叉验证集 multiprocessing 对不同的参数值重复这个过程,比如:

    import pandas as pd
    import numpy as np
    import multiprocessing as mp
    from sklearn.model_selection import StratifiedKFold
    
    #simulated datasets
    X = pd.DataFrame(np.random.randint(2, size=(3348,868), dtype='int8'))
    y = pd.Series(np.random.randint(2, size=3348, dtype='int64'))
    
    #dummy function to apply
    def _work(args):
        del(args)
    
    for C in np.arange(0.0,2.0e-3,1.0e-6):
        splitter = StratifiedKFold(n_splits=5)
        with mp.Pool(processes=5) as pool:
            pool_results = \
                pool.map(
                    func=_work,
                    iterable=((C,X.iloc[train_index],X.iloc[test_index]) for train_index, test_index in splitter.split(X, y))
                )
    

    然而,在执行过程的中途,我得到了以下错误:

    Traceback (most recent call last):
      File "mre.py", line 19, in <module>
        with mp.Pool(processes=5) as pool:
      File "/usr/lib/python3.5/multiprocessing/context.py", line 118, in Pool
        context=self.get_context())
      File "/usr/lib/python3.5/multiprocessing/pool.py", line 168, in __init__
        self._repopulate_pool()
      File "/usr/lib/python3.5/multiprocessing/pool.py", line 233, in _repopulate_pool
        w.start()
      File "/usr/lib/python3.5/multiprocessing/process.py", line 105, in start
        self._popen = self._Popen(self)
      File "/usr/lib/python3.5/multiprocessing/context.py", line 267, in _Popen
        return Popen(process_obj)
      File "/usr/lib/python3.5/multiprocessing/popen_fork.py", line 20, in __init__
        self._launch(process_obj)
      File "/usr/lib/python3.5/multiprocessing/popen_fork.py", line 67, in _launch
        self.pid = os.fork()
    OSError: [Errno 12] Cannot allocate memory
    

    我在Ubuntu 16.04上运行这个,内存为32GB,正在检查 htop 在执行过程中,它不会超过18.5GB,所以我不认为内存不足。
    这显然是由于我的数据帧与 splitter.split(X,y) 从我将数据帧直接传递给 Pool 对象没有引发错误。

    我看见了 this answer 这说明这可能是由于创建了太多的文件依赖关系,但我不知道如何解决这个问题,上下文管理器不应该帮助避免这种问题吗?

    1 回复  |  直到 6 年前
        1
  •  0
  •   torek    6 年前

    os.fork() 生成进程的副本,因此如果您的使用量约为18 GB,并且希望调用 fork ,您还需要18 GB。两次18是36 GB,远远超过32 GB。虽然这个分析是(有意)幼稚的,但有些东西并没有在fork上被复制,这可能足以解释这个问题。

    解决方案是在需要复制的内存较少的情况下更早地创建池,或者更努力地共享最大的对象。或者,当然,向系统添加更多的内存(可能只是虚拟内存,即交换空间)。