반응형
Step 5에서는 파이썬의 성능을 극대화하는 **병렬성(Parallelism)**과 **동시성(Concurrency)**을 다룹니다. 파이썬은 GIL(Global Interpreter Lock)이라는 제약이 있지만, 이를 우회하여 여러 작업을 동시에 처리하는 다양한 전략을 가지고 있습니다. CPU 집약적인 작업과 I/O 집약적인 작업을 어떻게 다르게 처리해야 하는지 배워봅시다.
1. 🚦 파이썬의 제약: GIL (Global Interpreter Lock)
파이썬(CPython)은 한 번에 하나의 스레드만 파이썬 바이트코드를 실행하도록 설계되어 있습니다. 이를 GIL이라고 합니다.
- 영향: 멀티 코어 환경에서도 멀티스레딩만으로는 CPU 연산 성능을 온전히 끌어올리기 어렵습니다.
- 해결책: CPU 연산이 많은 작업은 Multiprocessing을, 네트워크 요청 등 대기가 많은 작업은 Asyncio나 Threading을 사용합니다.
2. 🏗️ Multiprocessing: 진정한 병렬 처리
multiprocessing 모듈은 GIL을 우회하기 위해 여러 개의 프로세스를 생성합니다. 각 프로세스는 고유한 메모리 공간과 별도의 GIL을 가집니다.
- 용도: 데이터 분석, 이미지 처리, 암호화 등 CPU 연산이 집약적인 작업.
- 특징: 프로세스 간 통신(IPC) 비용이 발생하지만, 멀티 코어를 100% 활용할 수 있습니다.
Python
from multiprocessing import Process, current_process
def work():
print(f"작업 프로세스: {current_process().name}")
if __name__ == "__main__":
processes = []
for i in range(4): # 4개의 프로세스 생성
p = Process(target=work)
processes.append(p)
p.start()
for p in processes:
p.join()
3. ⚡ Asyncio: 단일 스레드 동시성
asyncio는 async와 await 키워드를 사용하여 비동기 프로그래밍을 지원합니다. 이벤트 루프(Event Loop)가 여러 작업을 전환하며 대기 시간을 효율적으로 활용합니다.
- 용도: 웹 크롤링, API 요청, 파일 입출력 등 네트워크/디스크 대기가 많은(I/O Bound) 작업.
- 특징: 스레드 스위칭 비용이 없어 매우 빠르고 가볍습니다.
Python
import asyncio
async def fetch_data():
print("데이터 요청 시작...")
await asyncio.sleep(2) # 비동기 대기
print("데이터 수신 완료!")
return {"data": 123}
async def main():
# 여러 비동기 작업을 동시에 실행
result = await asyncio.gather(fetch_data(), fetch_data())
print(result)
asyncio.run(main())
💡 시니어의 조언: 도구 선택의 기준
- CPU가 바쁘다(연산 위주): Multiprocessing을 선택하세요.
- CPU가 노는 시간이 많다(네트워크 대기 위주): Asyncio가 가장 효율적입니다.
- 단순히 여러 작업을 처리하고 싶다: 상황에 따라 Threading을 고려하되, 스레드 안전성(Thread Safety)에 주의해야 합니다.
반응형
'개발 > Python' 카테고리의 다른 글
| [고급반] Step 1. Pythonic Code & Meta: 파이썬답게 생각하고 코드를 설계하는 법 (0) | 2026.01.05 |
|---|---|
| [중급반] Step 6. 메타 프로그래밍과 자원 관리: Metaclass와 Context Manager (0) | 2025.12.26 |
| [중급반] Step 4. 제너레이터와 이터레이터: 메모리 효율의 극대화 (0) | 2025.12.26 |
| [중급반] Step 3. 객체 지향 프로그래밍(OOP) 심화: 상속과 MRO (0) | 2025.12.26 |
| [중급반] Step 2. 일급 함수와 클로저: 함수를 데이터처럼 다루기 (0) | 2025.12.26 |