Data Engineering/python

EP13 | 고급 Python 활용 #2 | 멀티스레딩과 멀티프로세싱

ygtoken 2025. 3. 19. 22:51
728x90

이 글에서 다루는 개념

Python에서 **멀티스레딩(Multithreading)과 멀티프로세싱(Multiprocessing)**을 사용하면
프로그램의 성능을 향상시키고, 여러 작업을 동시에 실행할 수 있습니다.
이번 글에서는 다음 내용을 학습합니다.

  • 멀티스레딩(threading 모듈) 개념과 활용
  • 멀티프로세싱(multiprocessing 모듈) 개념과 활용
  • 멀티스레딩 vs 멀티프로세싱 비교
  • GIL(Global Interpreter Lock)의 영향

1️⃣ 멀티스레딩(Multithreading) 개념과 활용

📌 스레드(Thread)란?

  • 스레드는 하나의 프로세스 내부에서 실행되는 독립적인 작업 단위입니다.
  • 여러 개의 스레드를 사용하면 하나의 프로그램에서 동시에 여러 작업을 수행할 수 있습니다.
  • Python에서는 threading 모듈을 사용하여 스레드를 관리합니다.

🔹 기본적인 멀티스레딩 예제

아래 코드에서는 두 개의 스레드가 동시에 실행됩니다.

import threading
import time

def task(name):
    for i in range(5):
        time.sleep(1)
        print(f"{name} 실행 중... {i+1}")

# 스레드 생성
thread1 = threading.Thread(target=task, args=("스레드 1",))
thread2 = threading.Thread(target=task, args=("스레드 2",))

# 스레드 실행
thread1.start()
thread2.start()

# 모든 스레드가 종료될 때까지 대기
thread1.join()
thread2.join()

print("모든 스레드 종료!")

📌 코드 설명

  • threading.Thread(target=함수, args=(인자,)) → 스레드 생성
  • .start() → 스레드 시작
  • .join() → 모든 스레드가 종료될 때까지 대기

2️⃣ 멀티프로세싱(Multiprocessing) 개념과 활용

📌 프로세스(Process)란?

  • 프로세스는 독립적으로 실행되는 프로그램 단위입니다.
  • 멀티프로세싱을 사용하면 여러 개의 CPU 코어를 활용하여 병렬 실행이 가능합니다.
  • Python에서는 multiprocessing 모듈을 사용합니다.

🔹 기본적인 멀티프로세싱 예제

import multiprocessing
import time

def task(name):
    for i in range(5):
        time.sleep(1)
        print(f"{name} 실행 중... {i+1}")

# 프로세스 생성
process1 = multiprocessing.Process(target=task, args=("프로세스 1",))
process2 = multiprocessing.Process(target=task, args=("프로세스 2",))

# 프로세스 실행
process1.start()
process2.start()

# 모든 프로세스 종료 대기
process1.join()
process2.join()

print("모든 프로세스 종료!")

📌 코드 설명

  • multiprocessing.Process(target=함수, args=(인자,)) → 프로세스 생성
  • .start() → 프로세스 시작
  • .join() → 모든 프로세스가 종료될 때까지 대기

3️⃣ 멀티스레딩 vs 멀티프로세싱 비교

항목 멀티스레딩(Threading) 멀티프로세싱(Multiprocessing)
실행 방식 하나의 프로세스 내에서 여러 작업 실행 여러 개의 독립된 프로세스 실행
GIL(Global Interpreter Lock) 영향 받음 영향 없음 (병렬 실행 가능)
CPU 바운드 작업 (계산) 비효율적 효율적
I/O 바운드 작업 (파일, 네트워크) 효율적 비효율적
메모리 사용량 적음 많음
속도 빠름 (GIL로 인해 한 번에 하나의 작업 실행) 더 빠름 (여러 CPU 코어 활용)

 

📌 언제 사용할까?

  • 멀티스레딩 → 네트워크 요청, 파일 I/O 등 I/O 바운드 작업
  • 멀티프로세싱 → CPU 연산이 많은 CPU 바운드 작업

4️⃣ GIL(Global Interpreter Lock)이란?

Python의 **GIL(Global Interpreter Lock)**은 한 번에 하나의 스레드만 실행되도록 제한하는 메커니즘입니다.

 

📌 GIL의 영향

  • 멀티스레딩을 사용해도 CPU 연산 작업에서는 병렬 실행이 불가능
  • I/O 바운드 작업(파일 입출력, 네트워크)에서는 GIL의 영향을 받지 않음

🔹 GIL을 확인하는 코드

import threading

count = 0

def increase():
    global count
    for _ in range(1000000):
        count += 1

# 두 개의 스레드 생성
thread1 = threading.Thread(target=increase)
thread2 = threading.Thread(target=increase)

# 스레드 실행
thread1.start()
thread2.start()

# 스레드 종료 대기
thread1.join()
thread2.join()

print("최종 count 값:", count)  # GIL 때문에 예상보다 작은 값이 나올 수 있음

💡 GIL을 우회하려면 multiprocessing을 사용하면 됨!


📌 실전 문제: 멀티스레딩과 멀티프로세싱 연습하기


문제 1: 멀티스레딩을 사용하여 동시에 두 개의 함수 실행하기

📌 두 개의 함수를 각각 스레드로 실행하여 동시에 출력하세요.

import threading
import time

def task1():
    # 🔽 여기에 코드 작성
import threading
import time

def task1():
    for i in range(3):
        time.sleep(1)
        print(f"Task 1 실행 중... {i+1}")

def task2():
    for i in range(3):
        time.sleep(1)
        print(f"Task 2 실행 중... {i+1}")

# 스레드 생성
thread1 = threading.Thread(target=task1)
thread2 = threading.Thread(target=task2)

# 실행
thread1.start()
thread2.start()

# 종료 대기
thread1.join()
thread2.join()

print("모든 스레드 종료!")

문제 2: 멀티프로세싱을 사용하여 두 개의 프로세스 실행하기

📌 두 개의 프로세스를 실행하여 각각 출력하세요.

import multiprocessing
import time

def process_task():
    # 🔽 여기에 코드 작성
import multiprocessing
import time

def process_task(name):
    for i in range(3):
        time.sleep(1)
        print(f"{name} 실행 중... {i+1}")

# 프로세스 생성
process1 = multiprocessing.Process(target=process_task, args=("프로세스 1",))
process2 = multiprocessing.Process(target=process_task, args=("프로세스 2",))

# 실행
process1.start()
process2.start()

# 종료 대기
process1.join()
process2.join()

print("모든 프로세스 종료!")

 

728x90