복붙노트

[PYTHON] 프로세스간에 클래스를 공유하려면 어떻게해야합니까?

PYTHON

프로세스간에 클래스를 공유하려면 어떻게해야합니까?

모든 프로세스가 최소한의 잠금으로 공유하고 업데이트하는 전역 개체를 갖고 싶습니다.

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()

결과는 10 점이 아니라 0 점입니다. 개체의 공유 값이 업데이트되지 않은 것 같습니다. 어떻게 이러한 값을 잠그고 업데이트 할 수 있습니까?

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.

@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()

해결법

  1. ==============================

    1.다중 처리. 값은 사용자 정의 클래스와 함께 사용하도록 설계되지 않았으므로 다중 처리. 공유 유형과 유사해야합니다. 값. 대신 사용자 정의 관리자를 만들어 클래스를 등록해야합니다. 값을 직접 액세스하지 않고 기본적으로 클래스에 대해 생성 된 기본 프록시에서 내보내는 메소드를 통해 수정 / 액세스하면 인생도 더 쉬울 것입니다. 일반 특성 (예 : Counter.value)은 추가 사용자 지정없이 액세스 할 수 없습니다. 다음은 실제 예제입니다.

    다중 처리. 값은 사용자 정의 클래스와 함께 사용하도록 설계되지 않았으므로 다중 처리. 공유 유형과 유사해야합니다. 값. 대신 사용자 정의 관리자를 만들어 클래스를 등록해야합니다. 값을 직접 액세스하지 않고 기본적으로 클래스에 대해 생성 된 기본 프록시에서 내보내는 메소드를 통해 수정 / 액세스하면 인생도 더 쉬울 것입니다. 일반 특성 (예 : 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()
    

    산출:

    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.
    
  2. from https://stackoverflow.com/questions/28612412/how-can-i-share-a-class-between-processes by cc-by-sa and MIT license