하나의 프로세스 내에서
여러 개의 스레드가 동시에 실행되며
작업을 병렬로 수행할 수 있는 실행 환경
Django 서버 자체가 하나의 프로세스
예를 들어, python manage.py runserver를 실행하면
하나의 프로세스가 생성됨
실제 배포 시에는 gunicorn, daphne, uvicorn 같은
WSGI/ASGI 서버가 여러 프로세스를 띄울 수도 있음
Django 서버 프로세스 내에서 클라이언트 요청을 처리하는 단위가 스레드
특히 StreamingHttpResponse로 구현된 SSE(streaming) 뷰는
클라이언트가 접속할 때마다
새로운 스레드 또는 비동기 태스크로 응답을 유지
# /map/sse_state.py
# 1단계: 전역 상태 저장 모듈 추가
# 이 모듈은 최신 위치 정보를 메모리에 저장하고 다른 곳에서 가져다 쓸 수 있게 함
import threading # threading 모듈은 멀티스레드 환경에서 데이터 동기화를 위해 사용됨
_latest_coords = [] # 위치 정보를 담아둘 전역 리스트 변수 (초기값은 빈 리스트)
_lock = threading.Lock() # 여러 스레드에서 동시에 접근할 때 충돌을 방지하기 위한 락(lock) 객체
# 최신 좌표 목록을 전역 변수에 안전하게 저장하는 함수
def set_latest_coords(coords):
with _lock: # 락을 걸고 시작 (다른 스레드가 동시에 수정하지 못하게)
global _latest_coords
_latest_coords = coords # 새로운 좌표 리스트로 갱신
# 최신 좌표 목록을 전역 변수에서 안전하게 복사해서 가져오는 함수
def get_latest_coords():
with _lock: # 읽을 때도 락을 걸어서 일관된 값을 보장
return _latest_coords.copy() # 복사본을 반환 (원본이 변하지 않도록)
#map/views.py
...
class SendUpdatedCoordinatesView(APIView):
permission_classes = [IsAuthenticated]
def get(self,request):
def event_stream(): # 이 내부 함수는 스트리밍 응답을 위해 무한 루프를 돌며 데이터를 계속 보냄
while True:
coords = get_latest_coords()
yield f"data : {json.dumps(coords)}\n\n"
# SSE 형식으로 데이터를 전송
# "data: ...\n\n" 형식은 SSE 프로토콜의 기본 구조
# 클라이언트에서는 이 데이터를 onmessage 이벤트로 받게 됨
# onmessage 이벤트 : SSE나 WebSocket 연결을 통해 서버로부터 받은 메시지를 클라이언트가 수신할 때 실행되는 이벤트 처리기
time.sleep(2) # 2초마다 반복해서 데이터를 전송 (브로드캐스트 간격 조절용)
return StreamingHttpResponse(event_stream(), content_type='text/event-stream')
# Django의 StreamingHttpResponse를 사용하여 스트리밍 응답을 생성
# content_type을 'text/event-stream'으로 설정해야 브라우저가 SSE로 인식함
...
이 코드는 여러 스레드가 동시에 _latest_coords에 접근할 수 있기 때문에 Lock()을 써서 동기화하고 있음
즉, 여러 사용자가
SendUpdatedCoordinatesView SSE 스트리밍을 동시에 요청하면,
각 요청이 스레드 단위로 처리되므로,
전역 상태인 _latest_coords를 안전하게 보호해야 하는 것
🖥️ 사용자 요청 1 ─┐
🖥️ 사용자 요청 2 ─┼──> [ Django 서버 프로세스 ]
🖥️ 사용자 요청 3 ─┘ │
│
┌──────────────────┴──────────────────┐
│ 스레드 1 │ ← 사용자 요청 1 처리
│ - patch() or get() 요청 처리 │
│ - set/get_latest_coords() 접근 │
└──────────────────────────────────────┘
│
┌──────────────────────────────────────┐
│ 스레드 2 │ ← 사용자 요청 2 처리
│ - SSE 응답 유지 (StreamingHttpResponse) │
│ - get_latest_coords() 주기적 호출 │
└──────────────────────────────────────┘
│
┌──────────────────────────────────────┐
│ 스레드 3 │ ← 사용자 요청 3 처리
│ - patch() 등으로 위치 업데이트 │
│ - set_latest_coords() 호출 │
└──────────────────────────────────────┘
📦 공유 자원: _latest_coords (전역 리스트)
🔒 동기화: threading.Lock()으로 스레드 간 충돌 방지