2016-08-05 8 views
2

1G共有配列を作成するためにPythonのmultiprocessing.Arrayを使用すると、pythonプロセスはmultiprocessing.Arrayの呼び出し中に約30Gのメモリを使用し、それ。なぜこれが起こっているのか把握して、それを回避する助けに感謝します。ここでpython multiprocessing.Array:巨大な一時メモリオーバーヘッド

はSMEMによって監視メモリと、Linux上でそれを再現するためのコードです:あなたはpythonの2を使用している、

pid of allocation process is 2285 
    PID User  Command       Swap  USS  PSS  RSS 
2116 ubuntu top        0  700  773  1044 
1442 ubuntu -bash        0  2020  2020  2024 
1751 ubuntu -bash        0  2492  2528  2700 
2284 ubuntu python test.py      0  1080  4566 11924 
2286 ubuntu /usr/bin/python /usr/bin/sm  0  4688  5573  7152 
2276 ubuntu python test.py      0  4000  8163 16304 
2285 ubuntu python test.py      0 137948 141431 148700 

    PID User  Command       Swap  USS  PSS  RSS 
2116 ubuntu top        0  700  773  1044 
1442 ubuntu -bash        0  2020  2020  2024 
1751 ubuntu -bash        0  2492  2528  2700 
2284 ubuntu python test.py      0  1188  4682 12052 
2287 ubuntu /usr/bin/python /usr/bin/sm  0  4696  5560  7160 
2276 ubuntu python test.py      0  4016  8174 16304 
2285 ubuntu python test.py      0 13260064 13263536 13270752 

    PID User  Command       Swap  USS  PSS  RSS 
2116 ubuntu top        0  700  773  1044 
1442 ubuntu -bash        0  2020  2020  2024 
1751 ubuntu -bash        0  2492  2528  2700 
2284 ubuntu python test.py      0  1188  4682 12052 
2288 ubuntu /usr/bin/python /usr/bin/sm  0  4692  5556  7156 
2276 ubuntu python test.py      0  4016  8174 16304 
2285 ubuntu python test.py      0 21692488 21695960 21703176 

    PID User  Command       Swap  USS  PSS  RSS 
2116 ubuntu top        0  700  773  1044 
1442 ubuntu -bash        0  2020  2020  2024 
1751 ubuntu -bash        0  2492  2528  2700 
2284 ubuntu python test.py      0  1188  4682 12052 
2289 ubuntu /usr/bin/python /usr/bin/sm  0  4696  5560  7160 
2276 ubuntu python test.py      0  4016  8174 16304 
2285 ubuntu python test.py      0 30115144 30118616 30125832 

    PID User  Command       Swap  USS  PSS  RSS 
2116 ubuntu top        0  700  771  1044 
1442 ubuntu -bash        0  2020  2020  2024 
1751 ubuntu -bash        0  2492  2527  2700 
2284 ubuntu python test.py      0  1192  4808 12052 
2290 ubuntu /usr/bin/python /usr/bin/sm  0  4700  5481  7164 
2276 ubuntu python test.py      0  4092  8267 16304 
2285 ubuntu python test.py      0 31823696 31827043 31834136 

    PID User  Command       Swap  USS  PSS  RSS 
2116 ubuntu top        0  700  771  1044 
1442 ubuntu -bash        0  2020  2020  2024 
1751 ubuntu -bash        0  2492  2527  2700 
2284 ubuntu python test.py      0  1192  4808 12052 
2291 ubuntu /usr/bin/python /usr/bin/sm  0  4700  5481  7164 
2276 ubuntu python test.py      0  4092  8267 16304 
2285 ubuntu python test.py      0 31823696 31827043 31834136 

Process Process-2: 
Traceback (most recent call last): 
    File "/usr/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap 
    self.run() 
    File "/usr/lib/python2.7/multiprocessing/process.py", line 114, in run 
    self._target(*self._args, **self._kwargs) 
    File "test.py", line 17, in allocate_shared_array 
    data=multiprocessing.Array(ctypes.c_ubyte,range(n)) 
    File "/usr/lib/python2.7/multiprocessing/__init__.py", line 260, in Array 
    return Array(typecode_or_type, size_or_initializer, **kwds) 
    File "/usr/lib/python2.7/multiprocessing/sharedctypes.py", line 115, in Array 
    obj = RawArray(typecode_or_type, size_or_initializer) 
    File "/usr/lib/python2.7/multiprocessing/sharedctypes.py", line 88, in RawArray 
    result = _new_value(type_) 
    File "/usr/lib/python2.7/multiprocessing/sharedctypes.py", line 63, in _new_value 
    wrapper = heap.BufferWrapper(size) 
    File "/usr/lib/python2.7/multiprocessing/heap.py", line 243, in __init__ 
    block = BufferWrapper._heap.malloc(size) 
    File "/usr/lib/python2.7/multiprocessing/heap.py", line 223, in malloc 
    (arena, start, stop) = self._malloc(size) 
    File "/usr/lib/python2.7/multiprocessing/heap.py", line 120, in _malloc 
    arena = Arena(length) 
    File "/usr/lib/python2.7/multiprocessing/heap.py", line 82, in __init__ 
    self.buffer = mmap.mmap(-1, size) 
error: [Errno 12] Cannot allocate memory 
+3

'range(n)'を 'xrange(n)'に置き換えた場合 –

答えて

3

あなたのprint文の形式から:ここで

import multiprocessing 
import ctypes 
import numpy 
import time 
import subprocess 
import sys 

def get_smem(secs,by): 
    for t in range(secs): 
     print subprocess.check_output("smem") 
     sys.stdout.flush() 
     time.sleep(by) 



def allocate_shared_array(n): 
    data=multiprocessing.Array(ctypes.c_ubyte,range(n)) 
    print "finished allocating" 
    sys.stdout.flush() 


n=10**9 
secs=30 
by=5 
p1=multiprocessing.Process(target=get_smem,args=(secs,by)) 
p2=multiprocessing.Process(target=allocate_shared_array,args=(n,)) 
p1.start() 
p2.start() 
print "pid of allocation process is",p2.pid 
p1.join() 
p2.join() 
p1.terminate() 
p2.terminate() 

が出力されます

range(n)xrange(n)に置き換えて、メモリを節約してください。試してみました

data=multiprocessing.Array(ctypes.c_ubyte,xrange(n)) 

(やPython 3を使用)

10億範囲はおよそ8ギガバイトを(!ちょうどそれをしないだけでなく、私はちょうど私のWindows PC上であることを試してみましたが、それが凍結した)かかり** 7 10とだけではなく、確かに:それは値に反復一つ一つを提供するので

>>> z=range(int(10**7)) 
>>> sys.getsizeof(z) 
80000064 => 80 Megs! you do the math for 10**9 

xrangeのようなジェネレータ関数は、メモリを取りません。 Pythonの3では

は、彼らはこれらの問題によってうんざりされている必要があり、ほとんどの人は、彼らが発電機を望んでいたので、rangeを使用xrangeを殺害し、発電機にrangeになっていることを考え出しました。あなたが本当に持っているすべての番号をlist(range(n))に割り当てたいのであれば、少なくとも、1テラバイトは間違って割り当てないでください!

編集:

私の説明は問題を解決しないという意味です。それは、少なくとも必要があるため、その後奇妙であるのpython 3(と7MBのまま500MBまでの2つの スロープのpythonで250MBのまま500MBまで

import multiprocessing,sys,ctypes 
n=10**7 

a=multiprocessing.RawArray(ctypes.c_ubyte,range(n)) # or xrange 
z=input("hello") 

スロープ:私は私のWindowsマシン上でいくつかの簡単なテストを行っていますあなたがPython 3であなたのプログラムを試して全体的なメモリピークが少ないかどうか確認できますか?

+1

残念なことに、この問題はあまりに単純ではありません。実際には、そのデータはディスクから読み込まれます。別の例として、n * ["a"]を使用し、マルチプロセッシングでc_charを指定することもできます。それは私がマルチプロセッシングに渡すリストに1Gのデータしか持っていないときでも約16Gを使用します.Array。私はいくつかの非効率な酸洗いが起こっているのか、そういうものがあるのだろうかと思っています。 – jeffdiamond

1

私はちょうど簡単な例としてそれを入れたので、残念ながら、問題はあまり範囲ではありません。実際には、そのデータはディスクから読み込まれます。別の例として、n * ["a"]を使用し、マルチプロセッシングでc_charを指定することもできます。それは私がマルチプロセッシングに渡すリストに1Gのデータしか持っていないときでも約16Gを使用します.Array。私はいくつかの非効率な酸洗いが起こっているのか、そういうものがあるのだろうかと思っています。

私はtempfile.SpooledTemporaryFileとnumpy.memmapを使用して、必要なものの回避策を見つけたようです。必要に応じてディスクにスプールされたメモリ内の一時ファイルにメモリマップを開き、それをマルチプロセッシングの引数として渡すことで、異なるプロセス間で共有することができます。

私はまだマルチプロセッシングで何が起こっているのか疑問に思っています。なぜ私は1Gのデータ配列に16Gを使用するのか分かりません。

+0

これは 'range'のために大丈夫です。再生産可能でスタンドアロンの例を投稿できますか? (まあ、ここで呼び出されるMVCE) –

+0

私はもっとテストしました。私の最後の編集を見てください –

関連する問題