
CPU(Central Processing Unit, 하드웨어)
1 코어는 한 번에 한 시점에 한 가지 일만 할 수 있습니다. 하지만, 인간이 동시 실행을 하고 싶기 때문에, 시간 분할 처리를 하여 동시 실행하는 것 처럼 보이게 하지만 한 번에 한가지 일을 할 때 가장 빠릅니다.
멀티 스레딩: I/O (CPU 바깥에서 일어나는 작업)이 쎌 때 유리함 - 키보드, 메모리, 네트워킹(통신) vs 멀티 프로세싱: CPU 안에서 일어나는 작업이 쎌 때 유리함
from concurrent.futures import ThreadPoolExecutor
모듈에서 제공하는 스레드 풀 구현체입니다. 이를 통해 병렬 처리를 쉽게 구현할 수 있습니다.
주요 특징 )
=> 주로 여러 웹 API를 동시에 호출하거나, 여러 파일을 동시에 처리하거나, 데이터베이스 쿼리를 병렬로 실행할 때 사용합니다.
=>CPU 집약적인 작업의 경우에는 ProcessPoolExecutor를 사용하는 것이 더 적합할 수 있습니다.
ProcessPoolExecutor : 스레드 대신 별도의 프로세스를 생성해서 작업을 처리합니다.
⭐️ThreadPoolExecutor과의 주요 차이점
각 작업이 별도의 프로세스에서 실행되어 메모리가 격리가 됩니다.
프로세스 생성 비용이 스레드보다 더 큽니다.
주로 대규모 수치계산, 이미지.비디오 처리, 데이터 분석, ML 모델학습 등에 사용됩니다.
@ GIL(Global Interpreter Lock) : Python의 메모리 관리를 위한 mutex(상호배제) 잠금 잠치입니다. 파이썬에서 한 번에 하나의 스레드만 파이썬 코드를 실행할 수 있도록 제한하는 메커니즘입니다.
# GIL로 인해 실제로는 병렬처리가 안되는 예시
import threading
counter = 0
def increment():
global counter
for _ in range(1000000):
counter += 1
# 두 개의 스레드 생성
thread1 = threading.Thread(target=increment)
thread2 = threading.Thread(target=increment)
# 스레드 실행
thread1.start()
thread2.start()
주요 특징
a ) 메모리 관리를 단순화하고 안전하게 함
b ) 단일 스레드 프로그램 성능 향상
c ) 하지만, 멀티코어 CPU에서 Python 스레드의 병렬 처리 제한
📌 이러한 제한을 우회하는 방법들 :
멀티 프로세싱 사용(ProcessPoolExecutor)
Numpy와 같은 C기반 라이브러리 사용
Cython사용
=> CPU 집약적인 작업을 할 때는 GIL을 우회할 수 있는 멀티프로세싱을 사용하는 것이 더 효율적
with ThreadPoolExecutor(max_workers=3) as executor:
with : Python의 컨텍스트 메니저를 시작합니다. 이는 리소스를 자동으로 관리해주는 구문입니다.
ThreadPoolExecutor(max_workers=3) : 최대 3개의 스레드를 가진 스레드 풀을 생성합니다.
max_worker = 3 는 동시에 실행될 수 있는 최대 스레드 수를 지정합니다.
as executor : 생성된 ThreadPoolExecutor 인스턴스를 executor 변수에 할당합니다.
=> 이 구문은 블록이 끝나면 자동으로 스레드 풀을 정리합니다. & 예외가 발생해도 안전하게 리소스를 해제합니다.