2012-02-13 8 views
7

実験と学習だけで、複数の処理でアクセスできる共有辞書を作成する方法はわかっていますが、辞書を同期させておく方法がわかりません。 defaultdict、私は、私が持っている問題を示していると信じています。defaultdictをマルチプロセッシングで使用しますか?

from collections import defaultdict 
from multiprocessing import Pool, Manager, Process 

#test without multiprocessing 
s = 'mississippi' 
d = defaultdict(int) 
for k in s: 
    d[k] += 1 

print d.items() # Success! result: [('i', 4), ('p', 2), ('s', 4), ('m', 1)] 
print '*'*10, ' with multiprocessing ', '*'*10 

def test(k, multi_dict): 
    multi_dict[k] += 1 

if __name__ == '__main__': 
    pool = Pool(processes=4) 
    mgr = Manager() 
    multi_d = mgr.dict() 
    for k in s: 
     pool.apply_async(test, (k, multi_d)) 

    # Mark pool as closed -- no more tasks can be added. 
    pool.close() 

    # Wait for tasks to exit 
    pool.join() 

    # Output results 
    print multi_d.items() #FAIL 

print '*'*10, ' with multiprocessing and process module like on python site example', '*'*10 
def test2(k, multi_dict2): 
    multi_dict2[k] += 1 


if __name__ == '__main__': 
    manager = Manager() 

    multi_d2 = manager.dict() 
    for k in s: 
     p = Process(target=test2, args=(k, multi_d2)) 
    p.start() 
    p.join() 

    print multi_d2 #FAIL 

最初の結果工事(そのがmultiprocessingを使用していないので)、私はそれがmultiprocessingで動作するようになって問題を抱えています。私はそれを解決する方法がわかりませんが、同期されていない(結果を後で結合する)ためかもしれないし、おそらくmultiprocessingの中にdefaultdict(int)を辞書に設定する方法がわからないからだと思います。

これをどのように動作させるかについての助けや提案は素晴らしいことでしょう。

答えて

10

あなたはBaseManagerのサブクラスを作成し、共有するための追加のタイプを登録することができます。デフォルトのAutoProxy生成タイプが機能しない場合は、適切なプロキシタイプを指定する必要があります。 defaultdictの場合は、既に存在する属性にアクセスする必要がある場合は、dictDictProxyを使用できます。

from multiprocessing import Pool 
from multiprocessing.managers import BaseManager, DictProxy 
from collections import defaultdict 

class MyManager(BaseManager): 
    pass 

MyManager.register('defaultdict', defaultdict, DictProxy) 

def test(k, multi_dict): 
    multi_dict[k] += 1 

if __name__ == '__main__': 
    pool = Pool(processes=4) 
    mgr = MyManager() 
    mgr.start() 
    multi_d = mgr.defaultdict(int) 
    for k in 'mississippi': 
     pool.apply_async(test, (k, multi_d)) 
    pool.close() 
    pool.join() 
    print multi_d.items() 
+1

うわー、うまくいって、ありがとう。私は本当にあなたの変更を理解していない、クラスMyManager(BaseManager)の目的は何ですか? – Lostsoul

+0

@Lostsoul Managerがサポートしているタイプ以外のタイプの共有をサポートするために、[文書化された方法](http://docs.python.org/library/multiprocessing.html#customized-managers)です。 –

+0

ありがとう、私はそれを勉強します! – Lostsoul

2

さて、Managerクラスは、プロセス間で共有できる固定数の事前定義されたデータ構造のみを提供していると思われ、defaultdictはそれらの間にありません。あなたは本当にただ1つdefaultdictが必要な場合は、最も簡単な解決策は、あなた自身の不履行動作を実装するために、次のようになります。

def test(k, multi_dict): 
    if k not in multi_dict: 
     multi_dict[k] = 0 
    multi_dict[k] += 1 
関連する問題