OSError:[Errno 12]使用python多处理池

时间:2019-01-25 11:06:27

标签: python scikit-learn multiprocessing

我正在尝试使用Python的multiprocessing将一个函数并行应用于5个交叉验证集,并针对不同的参数值重复该操作,如下所示:

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

我正在具有32Gb内存的Ubuntu 16.04上运行此程序,并在执行过程中检查htop,它永远不会超过18.5Gb,所以我不认为我的内存不足。
这肯定是由于我的数据帧与来自splitter.split(X,y)的索引分开造成的,因为当我直接将数据帧传递到Pool对象时,不会引发任何错误。

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

1 个答案:

答案 0 :(得分:2)

os.fork()复制了一个进程,因此,如果您的使用量约为18 GB,并且想调用fork,则还需要18 GB。两次18是36 GB,远远超过32 GB。尽管这种分析是(有意的)幼稚的(某些事情不会在fork上复制),但足以解释这个问题。

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