https://docs.python.org/3/tutorial/stdlib2.html#multi-threading

사용 예시

  • threading.Thread를 상속한 AsyncZip 클래스가 압축을 담당합니다.
  • 메인 스레드는 사용자 인터페이스를 계속 돌리고, 압축 스레드는 뒤에서 파일을 처리합니다.
import threading, zipfile
 
class AsyncZip(threading.Thread):
  def __init__(self, infile, outfile):
	  super().__init__()
	  self.infile = infile
	  self.outfile = outfile
 
  def run(self):
	  with zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED) as zf:
		  zf.write(self.infile)
	  print('압축 완료:', self.infile)
 
background = AsyncZip('data.txt', 'data.zip')
background.start()
print('메인 프로그램은 계속 실행 중입니다.')
 
background.join()  # 백그라운드 작업이 끝날 때까지 기다림
print('백그라운드 작업이 끝났습니다.')
  • 단일 관리자 스레드:
    • 공유 자원을 딱 한 스레드만 직접 다루게 하고, 나머지는 queue.Queue에 요청을 넣도록 설계하면 경합 자체를 없앨 수 있습니다.
    • 예컨대 DB 쓰기를 담당하는 전용 스레드가 큐에서 요청을 받아 처리하면 다른 스레드는 단순히 큐에 작업을 넣기만 하면 됩니다.
  • 작업 분리:
    • 한 스레드가 읽기/쓰기/업데이트를 동시에 하지 않게 책임을 분리합니다.
    • 읽기만 하는 스레드와 쓰기 담당 스레드를 나누거나,
    • 상태 변경은 특정 스레드에서만 하도록 규칙을 둡니다.
  • 동기화 최소화:
    • 꼭 공유해야 하는 데이터만 공유하고,
    • 나머지는 스레드별로 지역 상태를 유지합니다.
    • 필요 시 threading.Lock, RLock, Semaphore 등을 사용하되,
    • 잠금 범위를 최소한으로 줄여 데드락을 피합니다.
  • 불변 데이터 사용:
    • 가능하면 불변 객체(튜플, 문자열 등)를 공유하고,
    • 변경 가능한 구조는 복사본을 전달합니다.
    • 복사 비용이 적은 설정값,
    • 메시지 등은 이런 방식이 간단하고 안전합니다.
  • 테스트 및 로깅:
    • 스레드 간 타이밍 문제는 재현이 어려우므로, 큐 상태, 락 획득/반납 시점 등을 로그로 남기고,
    • 가능한 한 작은 단위로 테스트해 두면 문제 발생 시 추적이 쉬워집니다.
      ← python 3.14으로