web-dev-qa-db-ja.com

multiprocessing.pool.mapでkwargsを渡す

Pool.map()を使用してworker関数にキーワード引数を渡したいと思います。フォーラムを検索すると、この明確な例が見つかりません。

コード例:

_import multiprocessing as mp

def worker((x,y), **kwargs):
    kwarg_test = kwargs.get('kwarg_test', False)
    print("kwarg_test = {}".format(kwarg_test))     
    if kwarg_test:
        print("Success")
    return x*y

def wrapper_process(**kwargs):
    jobs = []
    pool=mp.Pool(4)
    for i, n in enumerate(range(4)):
        jobs.append((n,i))
    pool.map(worker, jobs) #works
    pool.map(worker, jobs, kwargs) #how to do this?   

def main(**kwargs):
    worker((1,2),kwarg_test=True) #accepts kwargs
    wrapper_process(kwarg_test=True)

if __name__ == "__main__":    
    main()
_

出力:

_kwarg_test = True
Success
kwarg_test = False
kwarg_test = False
kwarg_test = False
kwarg_test = False
TypeError: unsupported operand type(s) for //: 'int' and 'dict'
_

タイプエラーは、multiprocessing.PoolまたはQueue内の引数の解析に関係しており、kwargsのリストを作成するなど、他のいくつかの構文を試しました。 [kwargs、kwargs、kwargs、kwargs]、およびジョブリストにkwargを含めるためのいくつかの試みがありますが、運がありません。 multiprocessing.poolのコードをmapからmap_asyncまでトレースし、ジェネレーター構造に遭遇したときにpool.pyのtask_batches = Pool._get_tasks(func, iterable, chunksize)まで到達しました。私は将来これについてもっと学ぶことができてうれしいですが、今のところ私はただ見つけようとしています:

Pool.mapでkwargsの受け渡しを許可するための簡単な構文はありますか?

15
karl k

他の引数を繰り返し処理する場合は、@ ArcturusBの回答を使用してください。

反復ごとに同じ値を使用してそれらを渡すだけの場合は、次のようにすることができます。

from functools import partial
pool.map(partial(worker, **kwargs), jobs)

Partial '引数を関数にバインドします。古いバージョンのPython cannot ただし、部分オブジェクトをシリアル化します。

16
Mark

multiprocessing.pool.Pool.map doc 状態:

Map()組み込み関数と同等の並列機能(1つの反復可能な引数のみをサポートします)。結果の準備ができるまでブロックします。

反復可能な引数を1つだけ渡すことができます。話の終わり。しかし、幸運にも回避策を考えることができます。単一の引数を取り、それをargsとkwargsに解凍し、それらをworkerに渡すworker_wrapper関数を定義します。

def worker_wrapper(arg):
    args, kwargs = arg
    return worker(*args, **kwargs)

wrapper_processで、この単一の引数をjobsから(またはジョブを作成するときに直接)作成し、worker_wrapperを呼び出す必要があります。

arg = [(j, kwargs) for j in jobs]
pool.map(worker_wrapper, arg)

これが実際の実装であり、元のコードに可能な限り近づけています。

import multiprocessing as mp

def worker_wrapper(arg):
    args, kwargs = arg
    return worker(*args, **kwargs)

def worker(x, y, **kwargs):
    kwarg_test = kwargs.get('kwarg_test', False)
    # print("kwarg_test = {}".format(kwarg_test))     
    if kwarg_test:
        print("Success")
    else:
        print("Fail")
    return x*y

def wrapper_process(**kwargs):
    jobs = []
    pool=mp.Pool(4)
    for i, n in enumerate(range(4)):
        jobs.append((n,i))
    arg = [(j, kwargs) for j in jobs]
    pool.map(worker_wrapper, arg)

def main(**kwargs):
    print("=> calling `worker`")
    worker(1, 2,kwarg_test=True) #accepts kwargs
    print("=> no kwargs")
    wrapper_process() # no kwargs
    print("=> with `kwar_test=True`")
    wrapper_process(kwarg_test=True)

if __name__ == "__main__":    
    main()

テストに合格するもの:

=> calling `worker`
Success
=> no kwargs
Fail
Fail
Fail
Fail
=> with `kwar_test=True`
Success
Success
Success
Success
11
Arcturus B