私は次の問題に直面しています。ファイルを更新する関数を並列化しようとしていますが、_OSError: [Errno 12] Cannot allocate memory
_のためにPool()
を開始できません。私はサーバーを見回し始めました、そしてそれは私が古い、弱いもの/実際のメモリを使用しているようではありません。 htop
を参照してください: また、_free -m
_は、〜7GBのスワップメモリに加えて、RAMが利用可能であることを示しています: そして、私が使用しようとしているファイルもそれほど大きくありません。以下にコード(およびスタックトレース)を貼り付けます。サイズは次のとおりです。
使用されるpredictionmatrix
データフレームは約pandasdataframe.memory_usage()
によると80MBファイル_geo.geojson
_は2MBです
これをデバッグするにはどうすればよいですか?何をどのように確認できますか?ヒント/コツをありがとう!
コード:
_def parallelUpdateJSON(paramMatch, predictionmatrix, data):
for feature in data['features']:
currentfeature = predictionmatrix[(predictionmatrix['SId']==feature['properties']['cellId']) & paramMatch]
if (len(currentfeature) > 0):
feature['properties'].update({"style": {"opacity": currentfeature.AllActivity.item()}})
else:
feature['properties'].update({"style": {"opacity": 0}})
def writeGeoJSON(weekdaytopredict, hourtopredict, predictionmatrix):
with open('geo.geojson') as f:
data = json.load(f)
paramMatch = (predictionmatrix['Hour']==hourtopredict) & (predictionmatrix['Weekday']==weekdaytopredict)
pool = Pool()
func = partial(parallelUpdateJSON, paramMatch, predictionmatrix)
pool.map(func, data)
pool.close()
pool.join()
with open('output.geojson', 'w') as outfile:
json.dump(data, outfile)
_
スタックトレース:
_---------------------------------------------------------------------------
OSError Traceback (most recent call last)
<ipython-input-428-d6121ed2750b> in <module>()
----> 1 writeGeoJSON(6, 15, baseline)
<ipython-input-427-973b7a5a8acc> in writeGeoJSON(weekdaytopredict, hourtopredict, predictionmatrix)
14 print("Start loop")
15 paramMatch = (predictionmatrix['Hour']==hourtopredict) & (predictionmatrix['Weekday']==weekdaytopredict)
---> 16 pool = Pool(2)
17 func = partial(parallelUpdateJSON, paramMatch, predictionmatrix)
18 print(predictionmatrix.memory_usage())
/usr/lib/python3.5/multiprocessing/context.py in Pool(self, processes, initializer, initargs, maxtasksperchild)
116 from .pool import Pool
117 return Pool(processes, initializer, initargs, maxtasksperchild,
--> 118 context=self.get_context())
119
120 def RawValue(self, typecode_or_type, *args):
/usr/lib/python3.5/multiprocessing/pool.py in __init__(self, processes, initializer, initargs, maxtasksperchild, context)
166 self._processes = processes
167 self._pool = []
--> 168 self._repopulate_pool()
169
170 self._worker_handler = threading.Thread(
/usr/lib/python3.5/multiprocessing/pool.py in _repopulate_pool(self)
231 w.name = w.name.replace('Process', 'PoolWorker')
232 w.daemon = True
--> 233 w.start()
234 util.debug('added worker')
235
/usr/lib/python3.5/multiprocessing/process.py in start(self)
103 'daemonic processes are not allowed to have children'
104 _cleanup()
--> 105 self._popen = self._Popen(self)
106 self._sentinel = self._popen.sentinel
107 _children.add(self)
/usr/lib/python3.5/multiprocessing/context.py in _Popen(process_obj)
265 def _Popen(process_obj):
266 from .popen_fork import Popen
--> 267 return Popen(process_obj)
268
269 class SpawnProcess(process.BaseProcess):
/usr/lib/python3.5/multiprocessing/popen_fork.py in __init__(self, process_obj)
18 sys.stderr.flush()
19 self.returncode = None
---> 20 self._launch(process_obj)
21
22 def duplicate_for_child(self, fd):
/usr/lib/python3.5/multiprocessing/popen_fork.py in _launch(self, process_obj)
65 code = 1
66 parent_r, child_w = os.pipe()
---> 67 self.pid = os.fork()
68 if self.pid == 0:
69 try:
OSError: [Errno 12] Cannot allocate memory
_
[〜#〜]更新[〜#〜]
@robyschekのソリューションによると、コードを次のように更新しました。
_global g_predictionmatrix
def worker_init(predictionmatrix):
global g_predictionmatrix
g_predictionmatrix = predictionmatrix
def parallelUpdateJSON(paramMatch, data_item):
for feature in data_item['features']:
currentfeature = predictionmatrix[(predictionmatrix['SId']==feature['properties']['cellId']) & paramMatch]
if (len(currentfeature) > 0):
feature['properties'].update({"style": {"opacity": currentfeature.AllActivity.item()}})
else:
feature['properties'].update({"style": {"opacity": 0}})
def use_the_pool(data, paramMatch, predictionmatrix):
pool = Pool(initializer=worker_init, initargs=(predictionmatrix,))
func = partial(parallelUpdateJSON, paramMatch)
pool.map(func, data)
pool.close()
pool.join()
def writeGeoJSON(weekdaytopredict, hourtopredict, predictionmatrix):
with open('geo.geojson') as f:
data = json.load(f)
paramMatch = (predictionmatrix['Hour']==hourtopredict) & (predictionmatrix['Weekday']==weekdaytopredict)
use_the_pool(data, paramMatch, predictionmatrix)
with open('trentino-grid.geojson', 'w') as outfile:
json.dump(data, outfile)
_
それでも同じエラーが発生します。また、 documentation によると、map()
はdata
をチャンクに分割する必要があるため、80MBをrownum回複製する必要はないと思います。私は間違っているかもしれません... :)さらに、小さい入力(80MBではなく〜11MB)を使用しても、エラーが発生しないことに気づきました。ですから、メモリを使いすぎていると思いますが、80MBから16GBのRAMでは処理できないものになっていることは想像できません。
これは数回ありました。私のシステム管理者によると、unixには「バグ」があり、メモリが不足している場合や、プロセスがファイル記述子の最大制限に達した場合に同じエラーが発生します。
ファイル記述子のリークがあり、エラーが発生しました[Errno 12]メモリを割り当てることができません#012OSError。
したがって、スクリプトを調べて、問題がFDの作成が多すぎるのではないかどうかを再確認する必要があります。
multiprocessing.Pool
を使用する場合、プロセスを開始するデフォルトの方法はfork
です。 fork
の問題は、プロセス全体が重複していることです。 ( 詳細はこちら )。したがって、メインプロセスがすでに大量のメモリを使用している場合、このメモリは複製され、このMemoryError
に到達します。たとえば、メインプロセスが2GB
のメモリを使用し、8つのサブプロセスを使用する場合、RAMに18GB
が必要になります。
'forkserver'
や'spawn'
などの別の開始方法を使用してみてください。
from multiprocessing import set_start_method, Pool
set_start_method('forkserver')
# You can then start your Pool without each process
# cloning your entire memory
pool = Pool()
func = partial(parallelUpdateJSON, paramMatch, predictionmatrix)
pool.map(func, data)
これらのメソッドは、Process
のワークスペースの重複を回避しますが、使用しているモジュールをリロードする必要があるため、開始に少し時間がかかる場合があります。