Pool.map()が複数のパラメーターを持つ関数(この場合はLock()オブジェクト)をターゲットにできるように、部分的な関数を使用しようとしています。
以下にコードの例を示します(私の前の質問への回答から引用)。
from functools import partial
def target(lock, iterable_item):
for item in items:
# Do cool stuff
if (... some condition here ...):
lock.acquire()
# Write to stdout or logfile, etc.
lock.release()
def main():
iterable = [1, 2, 3, 4, 5]
pool = multiprocessing.Pool()
l = multiprocessing.Lock()
func = partial(target, l)
pool.map(func, iterable)
pool.close()
pool.join()
ただし、このコードを実行すると、エラーが発生します。
Runtime Error: Lock objects should only be shared between processes through inheritance.
ここで何が欠けていますか?サブプロセス間でロックを共有するにはどうすればよいですか?
申し訳ありませんが、他の質問への回答でこれを把握する必要がありました。通常の_multiprocessing.Lock
_オブジェクトをPool
メソッドに渡すことはできません。それらはピクルできないためです。これを回避するには2つの方法があります。 1つは、 Manager()
を作成し、 Manager.Lock()
を渡すことです。
_def main():
iterable = [1, 2, 3, 4, 5]
pool = multiprocessing.Pool()
m = multiprocessing.Manager()
l = m.Lock()
func = partial(target, l)
pool.map(func, iterable)
pool.close()
pool.join()
_
ただし、これは少し重いです。 Manager
を使用するには、Manager
サーバーをホストする別のプロセスを生成する必要があります。そして、acquire
/release
へのすべての呼び出しは、IPCを介してそのサーバーに送信する必要があります。
他のオプションは、initializer
kwargを使用して、プールの作成時に通常のmultiprocessing.Lock()
を渡すことです。これにより、すべての子ワーカーでロックインスタンスがグローバルになります。
_def target(iterable_item):
for item in items:
# Do cool stuff
if (... some condition here ...):
lock.acquire()
# Write to stdout or logfile, etc.
lock.release()
def init(l):
global lock
lock = l
def main():
iterable = [1, 2, 3, 4, 5]
l = multiprocessing.Lock()
pool = multiprocessing.Pool(initializer=init, initargs=(l,))
pool.map(target, iterable)
pool.close()
pool.join()
_
2番目のソリューションには、partial
が不要になるという副作用があります。
Windowsでも動作するバージョン(Barrier
の代わりにLock
を使用しますが、アイデアは得られます)(欠落しているfork
が追加のトラブルを引き起こしている):
import multiprocessing as mp
def procs(uid_barrier):
uid, barrier = uid_barrier
print(uid, 'waiting')
barrier.wait()
print(uid, 'past barrier')
def main():
N_PROCS = 10
with mp.Manager() as man:
barrier = man.Barrier(N_PROCS)
with mp.Pool(N_PROCS) as p:
p.map(procs, ((uid, barrier) for uid in range(N_PROCS)))
if __== '__main__':
mp.freeze_support()
main()