Cha*_*eon 11 python multiprocessing python-multiprocessing
我希望拥有全局对象,所有进程都以最小的锁定进行共享和更新.
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()
Run Code Online (Sandbox Code Playgroud)
结果是 - 不是10而是零.看起来该对象的共享值未更新.如何锁定和更新此值?
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.
Run Code Online (Sandbox Code Playgroud)
目前@dano的最佳解决方案 - 我将自定义管理器与类代理混合在一起.
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()
Run Code Online (Sandbox Code Playgroud)
dan*_*ano 15
multiprocessing.Value不是设计用于自定义类,它应该类似于a multiprocessing.sharedctypes.Value.相反,您需要创建一个自定义管理器并使用它注册您的类.如果您不value直接访问,您的生活也将更容易,但通过方法修改/访问它,默认情况下,这些方法将以默认Proxy为您的类创建的默认方式导出.常规属性(如Counter.value)不是,因此如果没有其他自定义,它们将无法访问.这是一个有效的例子:
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()
Run Code Online (Sandbox Code Playgroud)
输出:
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.
Run Code Online (Sandbox Code Playgroud)