2015-02-19 20 views
9

Tôi muốn có đối tượng chung được chia sẻ và cập nhật bởi tất cả các quy trình có khóa tối thiểu.Tôi làm cách nào để chia sẻ một lớp học giữa các quy trình?

import multiprocessing 

class Counter(object): 
    def __init__(self): 
    self.value = 0 

    def update(self, value): 
    self.value += value 


def update(counter_proxy, thread_id): 
    counter_proxy.value.update(1) 
    print counter_proxy.value.value, 't%s' % thread_id, \ 
    multiprocessing.current_process().name 
    return counter_proxy.value.value 

def main(): 
    manager = multiprocessing.Manager() 
    counter = manager.Value(Counter, Counter()) 
    pool = multiprocessing.Pool(multiprocessing.cpu_count()) 
    for i in range(10): 
    pool.apply(func = update, args = (counter, i)) 
    pool.close() 
    pool.join() 

    print 'Should be 10 but is %s.' % counter.value.value 

if __name__ == '__main__': 
    main() 

Kết quả là - không phải 10 nhưng không. Có vẻ như giá trị được chia sẻ của đối tượng không được cập nhật. Làm thế nào tôi có thể khóa và cập nhật giá trị như vậy?

0 t0 PoolWorker-2 
0 t1 PoolWorker-3 
0 t2 PoolWorker-5 
0 t3 PoolWorker-8 
0 t4 PoolWorker-9 
0 t5 PoolWorker-2 
0 t6 PoolWorker-7 
0 t7 PoolWorker-4 
0 t8 PoolWorker-6 
0 t9 PoolWorker-3 
Should be 10 but is 0. 

hiện các giải pháp tốt nhất bởi @dano - Tôi trộn quản lý tùy chỉnh với proxy lớp.

import multiprocessing 
from multiprocessing.managers import BaseManager, NamespaceProxy 


class Counter(object): 
    def __init__(self): 
    self.value = 0 

    def update(self, value): 
    self.value += value 


def update(counter_proxy, thread_id): 
    counter_proxy.update(1) 

class CounterManager(BaseManager): 
    pass 

class CounterProxy(NamespaceProxy): 
    _exposed_ = ('__getattribute__', '__setattr__', '__delattr__', 'update') 

    def update(self, value): 
    callmethod = object.__getattribute__(self, '_callmethod') 
    return callmethod(self.update.__name__, (value,)) 

CounterManager.register('Counter', Counter, CounterProxy) 

def main(): 
    manager = CounterManager() 
    manager.start() 

    counter = manager.Counter() 
    pool = multiprocessing.Pool(multiprocessing.cpu_count()) 
    for i in range(10): 
    pool.apply(func = update, args = (counter, i)) 
    pool.close() 
    pool.join() 

    print 'Should be 10 but is %s.' % counter.value 

if __name__ == '__main__': 
    main() 
+0

Làm sao bạn tìm hiểu về 'NamespaceProxy'? Tôi không thể tìm thấy tài liệu của nó ở đâu cả. – Seanny123

Trả lời

10

multiprocessing.Value không được thiết kế để được sử dụng với các lớp tùy chỉnh, nó cho là tương tự như một multiprocessing.sharedctypes.Value. Thay vào đó, bạn cần phải tạo một custom manager và đăng ký lớp học của bạn với nó. Cuộc sống của bạn cũng sẽ dễ dàng hơn nếu bạn không truy cập trực tiếp value nhưng hãy sửa đổi/truy cập thông qua các phương pháp sẽ được xuất theo mặc định Proxy được tạo cho lớp của bạn theo mặc định. Các thuộc tính thông thường (như Counter.value) không phải, vì vậy chúng không thể truy cập được nếu không có tùy chỉnh bổ sung. Dưới đây là một ví dụ làm việc:

import multiprocessing 
from multiprocessing.managers import BaseManager 

class MyManager(BaseManager): pass 

def Manager(): 
    m = MyManager() 
    m.start() 
    return m 

class Counter(object): 
    def __init__(self): 
    self._value = 0 

    def update(self, value): 
    self._value += value 

    def get_value(self): 
     return self._value 

MyManager.register('Counter', Counter) 

def update(counter_proxy, thread_id): 
    counter_proxy.update(1) 
    print counter_proxy.get_value(), 't%s' % thread_id, \ 
    multiprocessing.current_process().name 
    return counter_proxy 

def main(): 
    manager = Manager() 
    counter = manager.Counter() 
    pool = multiprocessing.Pool(multiprocessing.cpu_count()) 
    for i in range(10): 
    pool.apply(func=update, args=(counter, i)) 
    pool.close() 
    pool.join() 

    print 'Should be 10 but is %s.' % counter.get_value() 

if __name__ == '__main__': 
    main() 

Output:

1 t0 PoolWorker-2 
2 t1 PoolWorker-8 
3 t2 PoolWorker-4 
4 t3 PoolWorker-5 
5 t4 PoolWorker-6 
6 t5 PoolWorker-7 
7 t6 PoolWorker-3 
8 t7 PoolWorker-9 
9 t8 PoolWorker-2 
10 t9 PoolWorker-8 
Should be 10 but is 10. 
+0

Cảm ơn bạn đã đề xuất Tôi không biết rằng tôi có thể đăng ký các lớp học - có vẻ hay. Tôi tạo ra một số mã thay thế như thế này nhưng không có ý tưởng tại sao nó đang làm việc 'counter = counter_proxy.get(); counter.update (1); counter_proxy.set (counter) '- chỉ bằng cách gõ. Đó không phải là vấn đề nếu bạn đọc thuộc tính lớp, nó có thể được phát triển thành các thuộc tính, nó được sử dụng một cách đơn giản - tôi không theo các mẫu java mà tất cả phải được bọc thép lúc đầu - thích đơn giản lúc đầu - nó cho phép mã lớn hơn các kiểu Java . – Chameleon

+1

@Chameleon Trình trang trí '@ property' sẽ không hoạt động với loại' Proxy' mặc định. Nếu bạn thực sự muốn truy cập trực tiếp thuộc tính 'value', hãy xem [câu hỏi này] (http://stackoverflow.com/questions/26499548/accessing-an-attribute-of-a-multiprocessing-proxy-of-a -class) cho một cách để làm như vậy. – dano

+0

Có vẻ phức tạp. Tôi cần các ví dụ nghiên cứu. Dường như luồng thực sự là điểm yếu của Python - không phải tài liệu rất tốt với vài ví dụ cũng là vấn đề. Tốt điểm mà tôi nên sử dụng phương pháp. – Chameleon

Các vấn đề liên quan