4

ランダムな方法でnumpy配列と画像を同時に処理するpythonスクリプトがあります。生成されたプロセス内で適切なランダム性を持たせるために、メイン プロセスからワーカーにランダム シードを渡して、シードを与えます。

を使用するmaxtasksperchildと、何度もPool実行した後にスクリプトがハングしますPool.map

以下は、問題を再現する最小限のスニペットです。

# This code stops after multiprocessing.Pool workers are replaced one single time.
# They are replaced due to maxtasksperchild parameter to Pool
from multiprocessing import Pool
import numpy as np

def worker(n):
    # Removing np.random.seed solves the issue
    np.random.seed(1) #any seed value
    return 1234 # trivial return value

# Removing maxtasksperchild solves the issue
ppool = Pool(20 , maxtasksperchild=5)
i=0
while True:
    i += 1
    # Removing np.random.randint(10) or taking it out of the loop solves the issue
    rand = np.random.randint(10)
    l  = [3] # trivial input to ppool.map
    result = ppool.map(worker, l)
    print i,result[0]

これが出力です

1 1234
2 1234
3 1234
.
.
.
99 1234
100 1234 # この時点でワーカーは maxtasksperchild タスクに達しているはずです
101 1234
102 1234
103 1234
104 1234
105 1234
106 1234
107 1234
108 1234
109 1234
110 1234

その後、無期限にハングします。

私は潜在的にnumpy.randompythonのものに置き換えrandomて、問題を解決することができました。しかし、私の実際のアプリケーションでは、ワーカーは (ワーカーへの引数として与えられた) ユーザー コードを実行しますが、これは制御できずnumpy.random、そのユーザー コードで関数を使用できるようにしたいと考えています。そのため、意図的にグローバルランダムジェネレーターをシードしたいと考えています(各プロセスに対して個別に)。

これは、Python 2.7.10、numpy 1.11.0、1.12.0 & 1.13.0、Ubuntu、OSX でテスト済みです。

4

3 に答える 3

0

コメントに収まらないため、これを本格的な回答にします。

少し遊んだ後、ここに numpy.random バグのような匂いがします。フリーズ バグを再現することができました。さらに、発生してはならない奇妙なことがいくつかありました。たとえば、ジェネレーターの手動シードが機能しないなどです。

def rand_seed(rand, i):
    print(i)
    np.random.seed(i)
    print(i)
    print(rand())
def test1():
    with multiprocessing.Pool() as pool:
        [pool.apply_async(rand_seed, (np.random.random_sample, i)).get()
        for i in range(5)]
test1()

出力あり

0
0
0.3205032737431185
1
1
0.3205032737431185
2
2
0.3205032737431185
3
3
0.3205032737431185
4
4
0.3205032737431185

一方、引数として np.random.random_sample を渡さなくても問題なく動作します。

def rand_seed2(i):
    print(i)
    np.random.seed(i)
    print(i)
    print(np.random.random_sample())
def test2():
    with multiprocessing.Pool() as pool:
        [pool.apply_async(rand_seed, (i,)).get()
        for i in range(5)]
test2()

出力あり

0
0
0.5488135039273248
1
1
0.417022004702574
2
2
0.43599490214200376
3
3
0.5507979025745755
4
4
0.9670298390136767

これは、カーテンの後ろで重大ないたずらが行われていることを示唆しています。それについて他に何を言うべきかはわかりませんが....

基本的に、 numpy.random.seed は「シード状態」変数だけでなく、random_sample関数自体も変更するようです。

于 2017-06-12T23:14:16.080 に答える