안녕하세요! 그레이 해커 월횽입니다. 오늘은 Python에서 병렬 처리 및 멀티스레딩에 대해 알아보겠습니다. Python은 GIL(Global Interpreter Lock) 때문에 기본적으로 한 번에 하나의 스레드만 실행할 수 있습니다. 하지만 이를 극복하고 CPU의 여러 코어를 활용하여 성능을 높이기 위해 병렬 처리와 멀티스레딩을 사용할 수 있습니다. 이번 강의에서는 멀티스레딩, 멀티프로세싱 및 비동기 처리에 대해 다루겠습니다.
1. 병렬 처리와 멀티스레딩의 기본 개념
· 병렬 처리: 여러 작업을 동시에 실행하여 성능을 극대화하는 기법입니다. 보통 여러 CPU 코어를 활용하는 경우에 사용됩니다.
· 멀티스레딩: 하나의 프로세스 내에서 여러 스레드를 사용하여 작업을 동시에 실행하는 방식입니다. I/O 작업(파일 읽기/쓰기, 네트워크 통신)에서는 유용하지만, GIL로 인해 CPU 바운드 작업에서는 성능 개선이 제한적입니다.
2. threading 모듈을 사용한 멀티스레딩
Python에서 threading 모듈을 사용하면 간단하게 멀티스레딩을 구현할 수 있습니다. 주로 I/O 작업에서 유리합니다.
threading 모듈을 사용한 기본 스레드 예시
import threading
import time
# 스레드에서 실행할 함수 정의
def print_numbers():
for i in range(5):
print(f"Number: {i}")
time.sleep(1)
# 스레드 생성
thread = threading.Thread(target=print_numbers)
# 스레드 시작
thread.start()
# 메인 스레드에서 다른 작업 수행
print("메인 스레드에서 작업 중...")
# 스레드가 종료될 때까지 기다림
thread.join()
print("스레드 종료")
스레드 간 공유 자원 관리 (Lock 사용)
멀티스레딩 환경에서는 동시성 문제가 발생할 수 있으므로, Lock을 사용하여 공유 자원을 보호해야 합니다.
import threading
# 공유 변수
counter = 0
lock = threading.Lock()
# 스레드에서 실행할 함수
def increment_counter():
global counter
for _ in range(100000):
with lock: # Lock을 사용해 동시성 문제 방지
counter += 1
# 두 개의 스레드 생성
thread1 = threading.Thread(target=increment_counter)
thread2 = threading.Thread(target=increment_counter)
# 스레드 시작
thread1.start()
thread2.start()
# 두 스레드가 종료될 때까지 기다림
thread1.join()
thread2.join()
# 결과 출력
print(f"최종 카운터 값: {counter}")
3. multiprocessing 모듈을 사용한 병렬 처리
multiprocessing 모듈은 멀티프로세싱을 지원하여 GIL의 영향을 받지 않고 여러 프로세스를 생성하여 병렬로 작업을 처리할 수 있습니다.
multiprocessing 모듈을 사용한 병렬 처리 예시
import multiprocessing
# 프로세스에서 실행할 함수
def square_number(n):
return n * n
if __name__ == "__main__":
# 여러 프로세스에서 처리할 데이터
numbers = [1, 2, 3, 4, 5]
# 병렬 처리 풀 생성
with multiprocessing.Pool() as pool:
# 병렬로 작업 실행
results = pool.map(square_number, numbers)
print(results) # [1, 4, 9, 16, 25] 출력
multiprocessing.Queue를 사용한 프로세스 간 통신
멀티프로세스 간 통신을 위해 Queue를 사용할 수 있습니다.
import multiprocessing
# 자식 프로세스에서 실행할 함수
def worker(queue):
queue.put("작업 완료!")
if __name__ == "__main__":
# Queue 생성
queue = multiprocessing.Queue()
# 프로세스 생성
process = multiprocessing.Process(target=worker, args=(queue,))
# 프로세스 시작
process.start()
# 자식 프로세스의 결과 대기
print(queue.get())
# 프로세스 종료
process.join()
4. asyncio 모듈을 사용한 비동기 처리
asyncio는 비동기 방식으로 동시성을 처리할 수 있는 모듈입니다. 특히 I/O 바운드 작업에 적합하며, 멀티스레딩이나 멀티프로세싱에 비해 가볍고 효율적입니다.
asyncio로 비동기 함수 실행 예시
import asyncio
# 비동기 함수 정의
async def print_delayed(message, delay):
await asyncio.sleep(delay)
print(message)
# 메인 함수 정의
async def main():
task1 = asyncio.create_task(print_delayed("첫 번째 메시지", 2))
task2 = asyncio.create_task(print_delayed("두 번째 메시지", 1))
await task1
await task2
# 이벤트 루프 실행
asyncio.run(main())
5. 멀티스레딩, 멀티프로세싱, 비동기 처리 비교
· 멀티스레딩: I/O 바운드 작업에 적합하지만 GIL로 인해 CPU 바운드 작업에는 성능 제한이 있습니다.
· 멀티프로세싱: GIL의 영향을 받지 않고 CPU 코어를 모두 활용하여 병렬 처리 가능.
· 비동기 처리 (asyncio): 가벼운 동시성 처리로 I/O 바운드 작업에서 매우 효과적입니다.
6. 병렬 처리 및 멀티스레딩 정리
· threading 모듈을 통해 간단한 멀티스레딩을 구현할 수 있습니다.
· multiprocessing 모듈을 통해 GIL을 우회하고 병렬 처리를 구현할 수 있습니다.
· asyncio를 사용하여 비동기 방식으로 효율적인 동시성 처리를 구현할 수 있습니다.
다음 시간에는 Python을 활용한 네트워킹 프로그래밍에 대해 알아보겠습니다!
'프로그래밍 > Python' 카테고리의 다른 글
[Python 강의] 19강 - 웹 개발 기초 (0) | 2024.10.24 |
---|---|
[Python 강의] 18강 - 네트워킹 프로그래밍 (0) | 2024.10.23 |
[Python 강의] 16강 - 데이터베이스 관리 및 연결 (0) | 2024.10.21 |
[Python 강의] 15강 - 웹 스크래핑 기법 (0) | 2024.10.18 |
[Python 강의] 14강 - 다양한 데이터 분석 기법 (1) | 2024.10.17 |