파이썬 멀티스레딩과 threading 모듈 활용

스레드 기본 개념

스레드와 프로세스는 사용 방식과 스케줄링 전략이 유사하지만 본질적인 차이점은 다음과 같습니다:

  • 프로세스: 자원 할당 단위로, 독립된 메모리 공간을 나타냅니다
  • 스레드: 실행 단위로, 실제 코드 명령어를 실행합니다

하나의 프로세스 내에는 여러 개의 스레드가 존재할 수 있으며, 마치 하나의 공장에 여러 개의 생산 라인이 있는 것과 같습니다. 각 프로세스에는 최소한 하나의 스레드가 반드시 존재합니다.

프로세스 생성 시 필요한 리소스 소모가 크기 때문에, 동일한 프로세스 내에서 스레드를 생성하는 것이 훨씬 효율적입니다.

동일한 프로세스 내의 다중 스레드는 데이터를 공유하기 때문에 프로세스 간 데이터 격리와는 다릅니다.

스레드 생성 구현 방법

방법 1: 함수 기반

import threading
import time

def worker(identifier):
    print(f'{identifier} 작업 시작')
    time.sleep(0.1)
    print(f'{identifier} 작업 완료')

begin_time = time.time()
threads = []

# 100개의 스레드 동시 생성
for idx in range(100):
    thread = threading.Thread(target=worker, args=(f'작업자{idx}',))
    thread.start()
    threads.append(thread)

# 모든 스레드 종료 대기
for thread in threads:
    thread.join()

print(f"총 소요 시간: {time.time() - begin_time}")
# 0.11784076690673828

thread = threading.Thread(target=worker, args=('김철수',))
thread.start()
print('메인 스레드 계속 진행')

스레드 생성 시 전체 Python 파일의 리소스를 다시 로드하지 않고 새로운 실행 단위만 생성하므로, 프로세스 생성과 달리 main 문장을 추가할 필요가 없습니다.

여기서 볼 수 있듯이 원래 0.1초가 걸리는 작업을 100개 동시에 실행해도 시간이 거의 동일하지만, 동일한 작업을 100개의 프로세스로 실행하면 훨씬 더 많은 시간이 소요됩니다.

방법 2: 클래스 상속

import threading
import time

class WorkerThread(threading.Thread):
    def run(self):
        print('실행 중...')
        time.sleep(1)
        print('실행 완료')

worker_obj = WorkerThread()
worker_obj.start()
print('메인 스레드')

스레드 주요 특성

join 메서드

프로세스의 join 메서드와 동일하게, 메인 스레드가 하위 스레드가 종료될 때까지 대기합니다.

import threading
import time

def execute_task(name):
    print(f'{name} 실행 시작')
    time.sleep(1)
    print(f'{name} 실행 종료')

thread = threading.Thread(target=execute_task, args=('박영희',))
thread.start()
thread.join()
print('메인 스레드 종료')

데이터 공유 특성

import time
import threading

balance = 1001

def withdraw():
    time.sleep(0.2)
    global balance
    balance -= 100

thread_pool = []
for i in range(10):
    thread = threading.Thread(target=withdraw)
    thread.start()
    thread_pool.append(thread)

for thread in thread_pool:
    thread.join()

print(balance)  # 1

Event 객체 활용

Event는 여러 스레드 간의 작업 순서 조정을 도와주는 동기화 도구입니다.

import threading
import time

signal = threading.Event()

def traffic_light():
    print('빨간불: 모든 차량 정지')
    time.sleep(3)
    print('녹색불: 출발!')
    signal.set()

def vehicle(name):
    print(f'{name} 빨간불 대기 중')
    signal.wait()
    print(f'{name} 출발!')

# 신호등 스레드 시작
light_thread = threading.Thread(target=traffic_light)
light_thread.start()

# 20대의 차량 스레드 생성
for i in range(20):
    car_thread = threading.Thread(target=vehicle, args=(f'자동차{i:02d}',))
    car_thread.start()

기타 유틸리티 메서드

import threading

# 현재 실행 중인 스레드 이름 확인
print(threading.current_thread().name)

# 활성화된 스레드 수 확인
print(threading.active_count())

태그: python threading Multithreading concurrency synchronization

6월 10일 21:15에 게시됨