2012-02-13 25 views
7

Sadece deneme ve öğrenme, ve birden fazla işlemle erişilebilen bir paylaşılan sözlük nasıl oluşturulacağını biliyorum, ancak nasıl dict senkronize tutmak emin değilim. defaultdict, inanıyorum ki, sahip olduğum problemi gösteriyor.Çok işlemlerle varsayılanı kullanma?

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 

(onun multiprocessing kullanmıyor çünkü), ancak bunu elde sorunlar multiprocessing çalışmak yaşıyorum ilk sonuç çalışır. Bunu nasıl çözeceğimi bilmiyorum ama bunun senkronize edilmemesine (ve sonuçların daha sonra birleştirilmesine) veya belki de multiprocessing sözlüğüne sözlükte defaultdict(int)'un nasıl ayarlanacağını anlayamayacağımı düşünüyorum.

İşe nasıl başlayacağınıza dair herhangi bir yardım veya öneri harika olurdu!

cevap

10

Sen BaseManager alt sınıf ve paylaşım için ek türleri kaydedebilirsiniz. Varsayılan AutoProxy türetilmiş tipin çalışmadığı durumlarda uygun bir proxy türü sağlamanız gerekir. defaultdict için, yalnızca dict'da zaten var olan özniteliklere erişmeniz gerekiyorsa, DictProxy'u kullanabilirsiniz.

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

Wow, işe yaradı, teşekkürler. Değişikliklerinizi gerçekten anlamıyorum, Sınıf MyManager'ın (BaseManager) amacı nedir? – Lostsoul

+0

@Lostsoul Yöneticinin desteklediği diğer türlerin paylaşımına destek vermek için [belgelenmiş yol] (http://docs.python.org/library/multiprocessing.html#customized-managers). –

+0

Çok teşekkür ederim, ben çalışacağım! – Lostsoul

2

Manager sınıfı, yalnızca işlemler arasında paylaşılabilen sabit sayıda önceden tanımlanmış veri yapısı sağladığından ve defaultdict bunların arasında görünmüyor. Eğer gerçekten sadece bir defaultdict, kolay çözüm kendi başınıza varsaymak davranışı uygulamak olacağını gerekirse:

def test(k, multi_dict): 
    if k not in multi_dict: 
     multi_dict[k] = 0 
    multi_dict[k] += 1