안전한 데이터 공유
큐와 잠금 사용하기
안전한 데이터 공유은(는) CoddyKit의 무료 Python Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Python Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Python Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
경쟁 조건 문제
여러 스레드가 같은 데이터를 수정하면 작업 순서가 뒤섞여 결과가 손상될 수 있습니다. 이를 경쟁 조건이라고 합니다. 데이터를 안전하게 공유하려면 동기화 도구가 필요합니다.
import threading
counter = 0
def bump():
global counter
for _ in range(100000):
counter += 1
ts = [threading.Thread(target=bump) for _ in range(2)]
for t in ts: t.start()
for t in ts: t.join()
print('counter (may be < 200000):', counter)Lock으로 해결하기
threading.Lock은 한 번에 하나의 스레드만 임계 영역에 들어가도록 보장합니다. 공유 데이터를 수정하는 부분을 with 블록으로 감싸 잠금을 획득하세요.
import threading
counter = 0
lock = threading.Lock()
def bump():
global counter
for _ in range(100000):
with lock:
counter += 1
ts = [threading.Thread(target=bump) for _ in range(2)]
for t in ts: t.start()
for t in ts: t.join()
print('counter:', counter)acquire와 release
잠금은 acquire()와 release()를 사용하여 수동으로 다룰 수도 있지만, with 형식이 더 안전합니다. 오류가 발생해도 잠금을 해제하기 때문입니다.
import threading
lock = threading.Lock()
lock.acquire()
try:
print('inside critical section')
finally:
lock.release()
print('released')스레드 안전 큐
queue.Queue 클래스는 이미 스레드 안전성을 갖추고 있습니다. 스레드는 명시적인 잠금 없이 put과 get을 사용할 수 있으므로, 데이터를 전달할 때 선호되는 방법입니다.
import queue, threading
q = queue.Queue()
def producer():
for i in range(3):
q.put(i)
t = threading.Thread(target=producer)
t.start()
t.join()
while not q.empty():
print('got', q.get())생산자와 소비자
고전적인 패턴은 다음과 같습니다. 생산자는 작업을 큐에 put하고, 소비자는 작업을 get하여 처리합니다. 큐가 모든 잠금 처리를 담당합니다.
import queue, threading
q = queue.Queue()
results = []
def consumer():
while True:
item = q.get()
if item is None:
break
results.append(item * 10)
q.task_done()
t = threading.Thread(target=consumer)
t.start()
for i in range(3):
q.put(i)
q.put(None)
t.join()
print(results)join과 task_done
q.join()은 put된 모든 항목에 대응하는 task_done() 호출이 이루어질 때까지 실행을 멈춥니다. 이를 통해 주 스레드가 모든 작업이 끝날 때까지 기다릴 수 있습니다.
import queue, threading
q = queue.Queue()
def worker():
while True:
item = q.get()
q.task_done()
threading.Thread(target=worker, daemon=True).start()
for i in range(5):
q.put(i)
q.join()
print('all items processed')재진입을 위한 RLock
일반적인 Lock은 같은 스레드가 두 번 획득하려 하면 교착 상태에 빠집니다. threading.RLock(재진입 잠금)은 획득 횟수를 세면서 이를 허용합니다.
import threading
rlock = threading.RLock()
def outer():
with rlock:
inner()
def inner():
with rlock:
print('re-entered safely')
outer()신호 전달을 위한 Event
threading.Event를 사용하면 한 스레드가 다른 스레드에 신호를 보낼 수 있습니다. 스레드는 다른 스레드가 set()을 호출할 때까지 wait()를 호출합니다.
import threading
start = threading.Event()
def worker():
start.wait()
print('go!')
t = threading.Thread(target=worker)
t.start()
print('setting event')
start.set()
t.join()프로세스 간 공유
프로세스 간에는 대신 multiprocessing.Queue를 사용하세요. 이 큐는 서로 분리된 메모리 공간 사이에서 객체를 직렬화합니다.
import multiprocessing as mp
def producer(q):
for i in range(3):
q.put(i * i)
if __name__ == '__main__':
q = mp.Queue()
p = mp.Process(target=producer, args=(q,))
p.start()
p.join()
while not q.empty():
print('received', q.get())교착 상태 피하기
스레드가 서로의 잠금이 해제되기를 영원히 기다릴 때 교착 상태가 발생합니다. 여러 잠금을 획득해야 한다면 어디서나 항상 같은 순서로 획득하여 이를 피하세요.
import threading
lock_a = threading.Lock()
lock_b = threading.Lock()
def safe():
with lock_a:
with lock_b:
print('acquired in consistent order')
safe()잠금보다 큐 선호하기
가능하면 잠금으로 보호하는 변경 가능한 공유 상태보다 큐를 이용한 메시지 전달을 선호하세요. 이렇게 하면 동작을 더 쉽게 추론할 수 있고 버그가 생길 가능성도 훨씬 낮습니다.
import queue
q = queue.Queue()
for word in ['safe', 'simple', 'clear']:
q.put(word)
while not q.empty():
print(q.get())빠른 확인
데이터를 안전하게 공유하는 방법에 대한 이해도를 확인해 보세요.
복습
데이터를 안전하게 공유하는 방법을 배웠습니다:
- 보호되지 않은 공유 상태는 경쟁 조건으로 인해 손상됩니다.
Lock과RLock은 임계 영역을 보호합니다.queue.Queue는 스레드 안전하며, 프로세스 간에는multiprocessing.Queue를 사용하세요.Event는 스레드 간에 신호를 보내며, 일관된 잠금 순서를 사용하면 교착 상태를 피할 수 있습니다.
다음 과정: subprocess로 외부 프로그램 실행하기입니다.
자주 묻는 질문
“안전한 데이터 공유” 강의는 무료인가요?
네 — “안전한 데이터 공유” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Python Academy 강의 전체를 잠금 해제할 수 있습니다. Python Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“안전한 데이터 공유”에서 뭘 배우나요?
큐와 잠금 사용하기 브라우저에서 직접 실행하는 실습 코드로 Python Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Python Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Python Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“안전한 데이터 공유” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Python Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Python Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.