파이썬 SharedMemory 사용법 (mp.Value 와의 차이)
파이썬에서 shared memory 사용법을 알아보자.
참고로 서로 다른 프로세스 사이에 데이터를 전송하는 방법은 queue, pipe, shared memory 등이 있는데,
이 중에 shared memory가 가장 성능이 좋다.
다만 Lock 등을 잘 써야하는 단점이 있다.
파이썬에서 shared_memory는 multiprocessing.shared_memory 모듈을 통해 프로세스 간 데이터를 메모리를 통해 빠르게 공유할 수 있는 기능이다. Python 3.8 이상부터 기본 제공된다.
기본 개념은 아래와 같다.
- SharedMemory 객체를 생성해서 이름 기반으로 프로세스 간 공유
- numpy.ndarray나 byte buffer를 메모리에서 공유 가능
- 다른 프로세스는 이름으로 attach
주요 클래스와 함수는 아래와 같다.
- multiprocessing.shared_memory.SharedMemory
- multiprocessing.shared_memory.ShareableList
- multiprocessing.shared_memory.SharedMemoryManager (컨텍스트 매니저 지원)
사용 예시는 아래와 같다.
1) SharedMemory로 numpy 배열 공유
from multiprocessing import shared_memory
import numpy as np
# 원본 데이터 생성
a = np.array([1, 2, 3, 4, 5])
# 공유 메모리 생성
shm = shared_memory.SharedMemory(create=True, size=a.nbytes)
# 공유 메모리를 numpy 배열로 매핑
b = np.ndarray(a.shape, dtype=a.dtype, buffer=shm.buf)
# 데이터 복사
b[:] = a[:]
# 다른 프로세스에서는 shm.name을 사용해 접근 가능
print(f"Shared memory name: {shm.name}")
# 사용 후 정리
shm.close()
shm.unlink() # 마지막 프로세스에서 해제
2) ShareableList로 Python 리스트 공유
from multiprocessing import shared_memory
from multiprocessing.shared_memory import ShareableList
# ShareableList 생성
sl = ShareableList([1, 2, 3, 'hello'])
print(sl[3]) # 'hello'
# 이름으로 다른 프로세스에서 attach 가능
print(sl.shm.name)
# 정리
sl.shm.close()
sl.shm.unlink()
3) SharedMemoryManager로 리소스 자동 관리
from multiprocessing import shared_memory
from multiprocessing.managers import SharedMemoryManager
import numpy as np
with SharedMemoryManager() as smm:
shm = smm.SharedMemory(size=1024)
array = np.ndarray((256,), dtype=np.int32, buffer=shm.buf)
array[:] = np.arange(256)
print(array[10]) # 확인
# with 블록 종료 시 자동 unlink 및 close
주요 메서드 및 속성은 아래와 같다.
- SharedMemory(create=True/False, size, name=None)
- .buf : 버퍼에 접근
- .name : 공유 메모리 이름
- .close() : 현재 프로세스의 공유메모리 연결 해제
- .unlink() : 공유메모리 자체를 OS에서 삭제
주의할 점은...
- 메모리 크기를 미리 할당해야 함
- unlink()는 모든 프로세스가 사용을 끝낸 후 호출
- Windows에서는 다른 프로세스 attach 시 name만 필요
- 여러 프로세스에서 동시에 쓰는 경우에는 락(lock)을 직접 구현해주어야 함
그런데, 자세히 보면 SharedMemory와 SharedMemoryManager가 따로 있다.
이 둘의 차이는 무엇인지 확인해보자.
SharedMemory
먼저, SharedMemory는 단일 공유 메모리 블록을 직접 생성하고 관리할 때 사용하는 클래스이다.
📖 특징
- 메모리 블록을 직접 생성 (create=True)
- 생성한 메모리의 이름을 통해 다른 프로세스에서 attach 가능
- 메모리의 해제(close() + unlink())도 직접 처리
- numpy 배열이나 byte 버퍼 형태로 활용 가능
📌 언제 쓰냐?
- 공유할 메모리 블록이 몇 개 없고, 직접 메모리를 열고 닫는 작업을 관리해도 괜찮을 때
- 단순하게 한두 개의 데이터 블록을 공유할 때
SharedMemoryManager
그 다음으로 SharedMemoryManager는 여러 개의 SharedMemory 블록이나 ShareableList를 효율적으로 관리하는 컨텍스트 매니저이다.
📖 특징
- 컨텍스트 매니저(with)로 자원 관리를 자동으로 처리
- 내부적으로 SharedMemory와 ShareableList를 쉽게 생성하고 관리 가능
- with 블록이 끝나면 자동으로 close 및 unlink 처리
📌 언제 쓰냐?
- 공유 메모리 블록이 여러 개이거나, 여러 개의 ShareableList를 편하게 관리하고 싶을 때
- 프로세스 풀이나 병렬 처리 환경에서 리소스 누수 걱정 없이 공유 메모리를 쓸 때
즉, SharedMemory는 그냥 단순히 단일 메모리 블록을 할당할 때 사용하고,
SharedMemoryManager는 shared memory를 여러개 관리할 때, 자동으로 관리하고자 할 때 사용한다.
결론적으로는...
- 간단하게 공유 메모리 1~2개 쓸 거면 SharedMemory
- 여러 개를 쓴다거나 프로세스 풀/병렬 환경에서 리소스 누수 없이 관리하고 싶다면 SharedMemoryManager
그런데 multiprocessing 을 보다보면, mutiprocessing.Value 가 있고, 이것을 통해 프로세스간에 데이터 공유가 가능하다고 한다. SharedMemory랑 Value랑 차이는 뭔가?
📌 multiprocessing.Value는 SharedMemory 기반이 아님
multiprocessing.Value는 프로세스 간에 단일 값(숫자, 문자 등)을 공유하기 위한 객체
내부적으로 ctypes를 이용한 shared object로 구현돼 있고,
Python 3.8부터 도입된 multiprocessing.shared_memory 모듈의 SharedMemory와는 전혀 다른 방식임
📌 Value의 내부 동작
- POSIX에서는 mmap 또는 anonymous shared memory
- Windows에서는 named shared memory
- Python 3.8 이상이더라도 shared_memory.SharedMemory를 사용하지 않음
- 자원을 직접 close()/unlink() 할 필요 없이 프로세스가 끝날 때 자동 정리
그리고 Value 자체에 Lock 옵션이 내장되어 있어 동시 접근 제어도 가능
오, Value 자체에는 Lock 이 내장되어 있어, 동시 접근 제어도 가능하다는 것은 편리한 기능이 될 수 있다.
📌 Value vs SharedMemory
항목 | multiprocessing.Value | SharedMemory |
데이터 크기 | int, float, char 등 단일 값 | numpy array, byte buffer 등 대용량 |
메모리 관리 | 프로세스가 끝나면 자동 정리 | 직접 close(), unlink() 호출 필요 |
Lock 지원 | 내장 (옵션) | 없음 (직접 Lock 관리 필요) |
구현 방식 | ctypes 기반 shared object | Python 3.8+ multiprocessing.shared_memory |
SharedMemoryManager 사용 여부 | X | 필요 시 가능 |
정리해보면 아래와 같다.
- Value는 SharedMemory도 아니고 SharedMemoryManager도 아님
- 자체적으로 ctypes 기반의 shared object 구현
- 작은 단일 값 공유 시 가장 간편
- Lock 내장
그래서 결국 최종적으로는 이렇게 정리 될 수 있다.
상황 추천 방법
상황 | 추천방법 |
숫자 1~2개 공유 + 동기화 필요 | multiprocessing.Value |
리스트 형태 공유 + 동기화 필요 | multiprocessing.Array |
numpy 배열, 대용량 데이터 공유 | SharedMemory + Lock 직접 |
여러 공유 메모리/ShareableList 관리 | SharedMemoryManager |