다중 처리의 공유 메모리
큰 목록이 세 개 있습니다. 첫 번째는 비트 배열 (모듈 비트 배열 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
'Programing' 카테고리의 다른 글
파일 린트 메시지 처리 방법 : 경고 : 메서드가 함수일 수 있음 (0) | 2020.12.31 |
---|---|
Javascript에 소수점 두 개를 추가하면 잘못된 결과가 생성되는 이유는 무엇입니까? (0) | 2020.12.31 |
템플릿 인수 대체 순서가 중요한 이유는 무엇입니까? (0) | 2020.12.31 |
함수 반환 값은 자동 개체이므로 소멸이 보장됩니까? (0) | 2020.12.31 |
AppDomain 및 MarshalByRefObject 수명 : RemotingException을 피하는 방법? (0) | 2020.12.31 |