web-dev-qa-db-ja.com

multiprocessing.pool.mapと2つの引数を持つ関数

multiprocessing.Pool()を使用しています

これが私がプールしたいものです:

def insert_and_process(file_to_process,db):
    db = DAL("path_to_mysql" + db)
    #Table Definations
    db.table.insert(**parse_file(file_to_process))
    return True

if __name__=="__main__":
    file_list=os.listdir(".")
    P = Pool(processes=4)
    P.map(insert_and_process,file_list,db) # here having problem.

2つの引数を渡したい私がやりたいのは、4つのDB接続のみを初期化することです(ここでは、すべての関数呼び出しで接続を作成しようとするため、おそらく数百万の接続が発生し、IO凍結して死にます) 。4つのdb接続と各プロセスに1つを作成できれば、問題ありません。

プールの解決策はありますか?または私はそれを放棄する必要がありますか?

編集:

あなたの両方の助けから私はこれをすることによってこれを得ました:

args=Zip(f,cycle(dbs))
Out[-]: 
[('f1', 'db1'),
 ('f2', 'db2'),
 ('f3', 'db3'),
 ('f4', 'db4'),
 ('f5', 'db1'),
 ('f6', 'db2'),
 ('f7', 'db3'),
 ('f8', 'db4'),
 ('f9', 'db1'),
 ('f10', 'db2'),
 ('f11', 'db3'),
 ('f12', 'db4')]

それで、ここでそれがどのように機能するか、DB接続コードをメインレベルに移動してこれを行います:

def process_and_insert(args):

    #Table Definations
    args[1].table.insert(**parse_file(args[0]))
    return True

if __name__=="__main__":
    file_list=os.listdir(".")
    P = Pool(processes=4)

    dbs = [DAL("path_to_mysql/database") for i in range(0,3)]
    args=Zip(file_list,cycle(dbs))
    P.map(insert_and_process,args) # here having problem.

ええ、私はそれをテストして皆さんに知らせます。

10
Phyo Arkar Lwin

Poolのドキュメントには、ターゲット関数に複数のパラメーターを渡す方法については記載されていません。シーケンスを渡そうとしましたが、展開されません(パラメーターごとにシーケンスの1つの項目)。

ただし、最初の(そして唯一の)パラメーターがタプルであると期待するようにターゲット関数を作成できます。各要素は、期待するパラメーターの1つです。

from itertools import repeat

def insert_and_process((file_to_process,db)):
    db = DAL("path_to_mysql" + db)
    #Table Definations
    db.table.insert(**parse_file(file_to_process))
    return True

if __name__=="__main__":
    file_list=os.listdir(".")
    P = Pool(processes=4)
    P.map(insert_and_process,Zip(file_list,repeat(db))) 

insert_and_process- pythonの定義の余分な括弧は、2項目のシーケンスである必要がある単一のパラメーターとして扱います。シーケンスの最初の要素は、最初の変数、および2番目の変数)

26
jsbueno

プールは4つのプロセスを生成し、それぞれがPythonインタープリターの独自のインスタンスによって実行されます。グローバル変数を使用してデータベース接続オブジェクトを保持できるため、プロセスごとに1つの接続が作成されます。

_global_db = None

def insert_and_process(file_to_process, db):
    global global_db
    if global_db is None:
        # If this is the first time this function is called within this
        # process, create a new connection.  Otherwise, the global variable
        # already holds a connection established by a former call.
        global_db = DAL("path_to_mysql" + db)
    global_db.table.insert(**parse_file(file_to_process))
    return True
_

Pool.map()とその仲間は、引数が1つのワーカー関数しかサポートしていないため、作業を転送するラッパーを作成する必要があります。

_def insert_and_process_helper(args):
    return insert_and_process(*args)

if __name__ == "__main__":
    file_list=os.listdir(".")
    db = "wherever you get your db"
    # Create argument tuples for each function call:
    jobs = [(file, db) for file in file_list]
    P = Pool(processes=4)
    P.map(insert_and_process_helper, jobs)
_
8
Ferdinand Beyer

Zipを使用する必要はありません。たとえば、xとyの2つのパラメータがあり、それぞれが次のようないくつかの値を取得できる場合。

X=range(1,6)
Y=range(10)

関数は1つのパラメーターのみを取得し、それを内部で解凍する必要があります。

def func(params):
    (x,y)=params
    ...

そして、あなたはそれをそのように呼びます:

params = [(x,y) for x in X for y in Y]
pool.map(func, params)
5
Noam Peled

あなたが使用することができます

from functools import partial 

この目的のためのライブラリ

お気に入り

func = partial(rdc, lat, lng)
r = pool.map(func, range(8))

そして

def rdc(lat,lng,x):
    pass 
2
Mehmet nuri

使用する

params=[(x,y) for x in X for y in Y]

xyの完全なコピーを作成すると、使用するよりも時間がかかる場合があります

from itertools import repeat
P.map(insert_and_process,Zip(file_list,repeat(db)))
2
user1682580