[Python] multiprocessing 공유 딕셔너리 내부 값이 안 바뀔 때 해결법

lv2dev·2026년 3월 8일

Python 이것저것

목록 보기
8/8

파이썬에서 multiprocessing을 활용해 프로세스 간 데이터를 공유할 때 Manager().dict()를 자주 사용한다.

하지만 공유 딕셔너리 내부에 있는 중첩된(Nested) 값을 직접 수정할 경우, 변경 사항이 다른 프로세스에 동기화되지 않는 이슈가 발생한다. 본 글에서는 이 현상의 원인과 해결 방법을 정리한다.

1. 문제 상황

shared_config라는 공유 딕셔너리 내부에 ha_states라는 딕셔너리가 중첩되어 있다고 가정해 보자. 특정 상태가 변경될 때 값을 갱신하기 위해 아래와 같이 코드를 작성하는 경우가 많다.

실패하는 코드 (동기화 불가)

def update_ha_status(self, src: str, is_active: bool):
    # 공유 딕셔너리의 내부 뎁스(ha_states) 값을 직접 수정
    self.shared_config["ha_states"][src] = "ACT" if is_active else "STD"

위 코드를 실행하면 에러는 발생하지 않지만, 다른 프로세스에서는 갱신된 ha_states 값을 읽지 못한다.

2. 원인: Proxy 객체의 동작 방식

multiprocessing.Manager()가 반환하는 딕셔너리는 실제 파이썬 딕셔너리가 아니라, 상태 변경을 감지해 프로세스 간 전파를 담당하는 프록시(Proxy) 객체다.

이 프록시 객체의 핵심적인 특징은 자신의 최상위 키(Key)에 새로운 값이 명시적으로 할당(=)될 때만 변경을 감지한다는 점이다.

self.shared_config["ha_states"][src] = "ACT" 코드가 동작하는 과정을 단계별로 살펴보면 원인이 명확해진다.

  1. self.shared_config["ha_states"]를 호출하여 값을 꺼낸다. 이때 반환되는 것은 더 이상 프록시 객체가 아니라 일반 파이썬 딕셔너리다.
  2. 꺼내온 일반 딕셔너리의 [src] 키에 "ACT"를 할당한다.
  3. 결과적으로 최상위 프록시 객체인 shared_config 자체에는 어떠한 재할당 연산(=)도 발생하지 않았다. 따라서 프록시는 값의 변경을 알아채지 못하고 동기화도 수행하지 않는다.

3. 해결 방법: 전체 객체 재할당 (덮어쓰기)

프록시 객체가 상태 변경을 정상적으로 감지하게 하려면, 내부 딕셔너리를 꺼내어 수정한 뒤 수정된 전체 객체를 최상위 키에 통째로 다시 할당해야 한다.

성공하는 코드 (재할당 패턴)

def update_ha_status(self, src: str, is_active: bool):
    # 1. 기존 딕셔너리를 꺼내거나 새로 생성 (일반 딕셔너리 반환)
    states = self.shared_config.get("ha_states", {})
    
    # 2. 꺼내온 일반 딕셔너리의 값을 수정
    states[src] = "ACT" if is_active else "STD"
    
    # 3. 수정된 딕셔너리 전체를 최상위 키에 통째로 덮어쓰기 (재할당)
    self.shared_config["ha_states"] = states

마지막 줄의 self.shared_config["ha_states"] = states 처럼 할당 연산자(=)를 사용해 값을 덮어씌우면, 프록시 객체가 이를 감지하여 모든 프로세스에 변경 사항을 즉시 동기화한다.

4. 요약

multiprocessing.Manager().dict() 등의 공유 메모리 객체를 사용할 때, 내부의 중첩된 자료형(딕셔너리, 리스트 등)을 갱신하려면 반드시 값을 꺼내어 수정한 뒤 통째로 재할당해야 한다. 멀티프로세싱 환경에서 흔히 겪을 수 있는 함정이므로 구조 설계 시 주의가 필요하다.

profile
언제나 레벨업을 하고 싶은 영원한 lv1

0개의 댓글