web-dev-qa-db-ja.com

マルチプロセッシングIOError:メッセージの長さが正しくありません

大きな引数をmap関数に渡すと、IOError: bad message lengthが返されます。どうすればこれを回避できますか? N=1500以上を設定するとエラーが発生します。

コードは次のとおりです。

import numpy as np
import multiprocessing

def func(args):
    i=args[0]
    images=args[1]
    print i
    return 0

N=1500       #N=1000 works fine

images=[]
for i in np.arange(N):
    images.append(np.random.random_integers(1,100,size=(500,500)))

iter_args=[]
for i in range(0,1):
    iter_args.append([i,images])

pool=multiprocessing.Pool()
print pool
pool.map(func,iter_args)

multiprocessingのドキュメントには、IOErrorを発生させる関数recv_bytesがあります。これが原因でしょうか? ( https://python.readthedocs.org/en/v2.7.2/library/multiprocessing.html

[〜#〜] edit [〜#〜]リストの代わりにimagesをnumpy配列として使用すると、別のエラー:SystemError: NULL result without error in PyObject_Call。少し異なるコード:

import numpy as np
import multiprocessing

def func(args):
    i=args[0]
    images=args[1]
    print i
    return 0

N=1500       #N=1000 works fine

images=[]
for i in np.arange(N):
    images.append(np.random.random_integers(1,100,size=(500,500)))
images=np.array(images)                                            #new

iter_args=[]
for i in range(0,1):
    iter_args.append([i,images])

pool=multiprocessing.Pool()
print pool
pool.map(func,iter_args)

EDIT2私が使用する実際の関数は次のとおりです。

def func(args):
    i=args[0]
    images=args[1]
    image=np.mean(images,axis=0)
    np.savetxt("image%d.txt"%(i),image)
    return 0

さらに、iter_argsには同じ画像のセットが含まれていません。

iter_args=[]
for i in range(0,1):
    Rand_ind=np.random.random_integers(0,N-1,N)
    iter_args.append([i,images[Rand_ind]])
21
Andy

これが問題を解決したものです。画像をグローバルに宣言します。

import numpy as np
import multiprocessing


N=1500       #N=1000 works fine

images=[]
for i in np.arange(N):
    images.append(np.random.random_integers(1,100,size=(500,500)))

def func(args):
    i=args[0]
    images=images
    print i
    return 0

iter_args=[]
for i in range(0,1):
    iter_args.append([i])

pool=multiprocessing.Pool()
print pool
pool.map(func,iter_args)
1
Andy

プールを作成し、すべての画像を一度にfunc()に送信します。一度に1つの画像で作業するのをやめることができる場合は、次のようなものを試してください。これは、35秒でN = 10000で完了し、Python 2.7.10:

import numpy as np
import multiprocessing

def func(args):
    i = args[0]
    img = args[1]
    print "{}: {} {}".format(i, img.shape, img.sum())
    return 0

N=10000

images = ((i, np.random.random_integers(1,100,size=(500,500))) for i in xrange(N))
pool=multiprocessing.Pool(4)
pool.imap(func, images)
pool.close()
pool.join()

ここで重要なのは、イテレータを使用することです。これにより、すべてのデータを一度にメモリに保持する必要がなくなります。たとえば、すべてのデータを保持する配列からジェネレータ式に画像を変換して、必要な場合にのみ画像を作成しました。これを変更して、ディスクなどからイメージをロードできます。また、pool.mapの代わりにpool.imapを使用しました。

可能であれば、ワーカー関数に画像データをロードしてみてください。現在、すべてのデータをシリアル化して、別のプロセスに送信する必要があります。画像データが大きい場合、これがボトルネックになる可能性があります。

[funcがすべての画像を一度に処理する必要があることがわかったので更新]

画像に対して反復的な意味を実行できます。マルチプロセッシングを使用しないソリューションを次に示します。マルチプロセッシングを使用するには、画像をチャンクに分割し、それらのチャンクをプールにファームアウトします。

import numpy as np

N=10000
shape = (500,500)

def func(images):
    average = np.full(shape, 0)
    for i, img in images:
        average += img / N
    return average

images = ((i, np.full(shape,i)) for i in range(N))

print func(images)
11
Joseph Sheedy

プログラムを実行すると、実際には明確なエラーが発生します。

OSError: [Errno 12] Cannot allocate memory

他のユーザーが述べているように、問題の解決策は、メモリを(大量に)追加するか、プログラムが画像を処理する方法を変更することです。

大量のメモリを使用している理由は、モジュールレベルで画像にメモリを割り当てるためです。したがって、マルチプロセスがプロセスをフォークすると、すべての画像もコピーされます(これは、 pythonマルチプロセッシング の共有メモリオブジェクト)によると無料ではありません)、これは必要ありません。また、マルチプロセスモジュールがipcとpickleを使用してコピーする関数の引数として画像を指定している場合でも、メモリが不足する可能性があります。他のユーザーから提案されたソリューションの1つを試してください。

1
joebie13

PythonはデータをRAMメモリにロードする可能性があり、このメモリを使用できるようにする必要があります。コンピュータのメモリ使用量を確認しましたか?

また、Patrickが述べたように、3 GBのデータをロードしているので、32ビットのメモリ制約に達しているので64ビットバージョンのPythonを使用してください。これにより、プロセスがクラッシュする可能性があります。 2ビットと64ビットのPython

もう1つの改善点は、2.7ではなくpython 3.4を使用することです。Python 3の実装は、非常に広い範囲に最適化されているようです。 Python3とPython2)を参照してください。リスト/ジェネレーター範囲のパフォーマンス

1
user4453877