Programing

다중 처리의 공유 메모리

crosscheck 2020. 12. 31. 22:49
반응형

다중 처리의 공유 메모리


큰 목록이 세 개 있습니다. 첫 번째는 비트 배열 (모듈 비트 배열 0.8.0)을 포함하고 다른 두 개는 정수 배열을 포함합니다.

l1=[bitarray 1, bitarray 2, ... ,bitarray n]
l2=[array 1, array 2, ... , array n]
l3=[array 1, array 2, ... , array n]

이러한 데이터 구조는 상당한 RAM (총 16GB)을 차지합니다.

다음을 사용하여 12 개의 하위 프로세스를 시작하면

multiprocessing.Process(target=someFunction, args=(l1,l2,l3))

이것은 l1, l2 및 l3이 각 하위 프로세스에 대해 복사되거나 하위 프로세스가 이러한 목록을 공유한다는 것을 의미합니까? 아니면 좀 더 직접적으로 16GB 또는 192GB RAM을 사용합니까?

someFunction은이 목록에서 일부 값을 읽은 다음 읽은 값에 따라 일부 계산을 수행합니다. 결과는 상위 프로세스로 반환됩니다. l1, l2 및 l3 목록은 someFunction에 의해 수정되지 않습니다.

따라서 하위 프로세스가 필요하지 않으며 이러한 거대한 목록을 복사하지 않고 대신 부모와 공유 할 것이라고 가정합니다. Linux에서 copy-on-write 접근 방식으로 인해 프로그램이 시작하는 하위 프로세스 수에 관계없이 16GB RAM을 사용한다는 의미입니까? 내가 정확합니까 아니면 목록이 복사되는 원인이되는 것이 있습니까?

편집 : 주제에 대해 조금 더 읽은 후에도 여전히 혼란 스럽습니다. 한편으로 Linux는 copy-on-write를 사용하므로 데이터가 복사되지 않습니다. 반면에 객체에 액세스하면 ref-count가 변경됩니다 (아직도 그 이유와 의미를 잘 모르겠습니다). 그래도 전체 개체가 복사됩니까?

예를 들어 다음과 같이 someFunction을 정의하면 :

def someFunction(list1, list2, list3):
    i=random.randint(0,99999)
    print list1[i], list2[i], list3[i]

이 기능을 사용하면 l1, l2 및 l3이 각 하위 프로세스에 대해 완전히 복사된다는 것을 의미합니까?

이것을 확인하는 방법이 있습니까?

EDIT2 하위 프로세스가 실행되는 동안 조금 더 읽고 시스템의 총 메모리 사용량을 모니터링 한 후 전체 개체가 실제로 각 하위 프로세스에 대해 복사되는 것 같습니다. 그리고 그것은 참조 계수 때문인 것 같습니다.

l1, l2 및 l3에 대한 참조 계산은 실제로 내 프로그램에서 필요하지 않습니다. 이는 l1, l2 및 l3이 부모 프로세스가 종료 될 때까지 메모리 (변경되지 않음)에 유지되기 때문입니다. 그때까지는 이러한 목록에서 사용하는 메모리를 해제 할 필요가 없습니다. 실제로 프로그램이 종료 될 때까지 참조 횟수가 0 (이 목록과 이러한 목록의 모든 개체에 대해) 이상으로 유지된다는 것을 알고 있습니다.

이제 질문은 객체가 각 하위 프로세스에 복사되지 않도록 어떻게 확인할 수 있습니까? 이 목록과이 목록의 각 개체에 대한 참조 계산을 비활성화 할 수 있습니까?

EDIT3 추가 메모입니다. 하위 프로세스를 수정할 필요가 없습니다 l1, l2그리고 l3이러한 목록에있는 모든 오브젝트 또는. 하위 프로세스는 각 하위 프로세스에 대해 메모리를 복사하지 않고 이러한 개체 중 일부만 참조 할 수 있어야합니다.


일반적으로 동일한 데이터를 공유하는 방법에는 두 가지가 있습니다.

  • 멀티 스레딩
  • 공유 메모리

Python의 멀티 스레딩은 GIL로 인해 CPU 바운드 작업에 적합하지 않으므로이 경우 일반적인 솔루션은 계속하는 것입니다 multiprocessing. 그러나이 솔루션에서는 multiprocessing.Value및을 사용하여 데이터를 명시 적으로 공유해야합니다 multiprocessing.Array.

모든 동기화 문제 때문에 일반적으로 프로세스간에 데이터를 공유하는 것이 최선의 선택이 아닐 수 있습니다. 행위자가 메시지를 교환하는 방식이 일반적으로 더 나은 선택으로 간주됩니다. Python 문서 도 참조하십시오 .

위에서 언급했듯이 동시 프로그래밍을 할 때 일반적으로 가능한 한 공유 상태를 사용하지 않는 것이 가장 좋습니다. 여러 프로세스를 사용할 때 특히 그렇습니다.

그러나 실제로 일부 공유 데이터를 사용해야하는 경우 다중 처리는이를 수행하는 몇 가지 방법을 제공합니다.

귀하의 경우에는, 당신은 랩에 필요 l1, l2그리고 l3이해할 어떤 식 으로든 multiprocessing(A를 사용하여 예 multiprocessing.Array) 다음 매개 변수로 전달합니다.
또한 쓰기 액세스가 필요하지 않다고 말했듯이 lock=False객체를 만드는 동안 전달해야합니다. 그렇지 않으면 모든 액세스가 계속 직렬화됩니다.


Copy-on-write 기능을 사용하고 데이터가 정적 인 경우 (하위 프로세스에서 변경되지 않음)-Python이 데이터가있는 메모리 블록을 엉망으로 만들지 않도록해야합니다. C 또는 C ++ 구조 (예 : stl)를 컨테이너로 사용하여 쉽게이 작업을 수행 할 수 있으며, 파이썬 수준 객체가 생성 될 때 데이터 메모리에 대한 포인터 (또는 가능하면 데이터 mem 복사)를 사용할 고유 한 파이썬 래퍼를 제공 할 수 있습니다. . 이 모든 것은 거의 파이썬의 단순성과 cython 구문으로 매우 쉽게 할 수 있습니다 .

# 유사 사이 톤
cdef 클래스 FooContainer :
   cdef char * 데이터
   def __cinit __ (self, char * foo_value) :
       self.data = malloc (1024, sizeof (char))
       memcpy (self.data, foo_value, min (1024, len (foo_value)))

   def get (self) :
       self.data 반환

# 파이썬 부분
foo에서 가져 오기 FooContainer

f = FooContainer ( "안녕하세요")
pid = 포크 ()
pid가 아닌 경우 :
   f.get () #이 호출은 동일한 메모리 페이지를 어디에
           # 부모 프로세스가 1024 자 self.data 작성
           # 그리고 cython은 자동으로 새로운 파이썬 문자열을 생성합니다
           # 개체에서 호출자에게 반환

위의 의사 코드는 잘못 작성되었습니다. 그것을 사용하지 마십시오. self.data 대신 귀하의 경우 C 또는 C ++ 컨테이너가되어야합니다.


memcached 또는 redis를 사용하고 각각을 키 값 쌍 { 'l1'...으로 설정할 수 있습니다.

참조 URL : https://stackoverflow.com/questions/14124588/shared-memory-in-multiprocessing

반응형