Python 개념 & 성능 최적화

멀티스레딩과 멀티프로세싱의 차이

CodeWithBeam 2025. 4. 2. 22:34

멀티스레딩 (Multi-threading)

➡️하나의 프로세스 내에서 여러 스레드(Thread)를 실행(메모리 공유, 같은 자원에 접근 가능)

 

특징

  • 경량 실행 단위 (스레드 간 메모리 공유)
  • I/O 작업에 유리 (ex. 파일 읽기/쓰기, 네트워크 요청 등)
  • 파이썬은 GIL(Global Interpreter Lock)의 영향을 받아서 한 시점에 하나의 스레드만 실행됨 → CPU 연산에서는 병렬 처리 효과가 떨어짐.

멀티프로세싱 (Multi-processing)

➡️ 여러 프로세스(Process-> 독립된 메모리 공간)를 생성해서 병렬로 실행

 

특징

  • CPU 연산에 유리 (병렬 계산 가능)
  • GIL의 영향을 받지 않음 → 진정한 병렬 처리 가능
  • 프로세스 간 통신(IPC)은 비교적 비용이 큼 (Queue, Pipe 등 사용)

✅ 간단 정리

실행 단위 스레드(Thread) 프로세스(Process)
메모리 공유 공유 독립적
GIL 영향 O X
병렬 처리 I/O에 적합 CPU 연산에 적합
메모리 사용 적음 많음
속도 빠를 수 있음 (I/O) CPU 코어 수만큼 병렬 처리 가능

 

프로세스(Process)란?

➡️ 운영체제에서 실행중인 프로그램 하나

ex)문서를 여는 순간, 크롬을 켜는 순간 하나의 프로세스가 실행됨

 

특징

  • 하나의 프로세스는 독립된 메모리 공간을 가지고 있다.(다른 프로세스와 메모리 공유X) -> 안정성이 높다.
  •                "               자원을 독립적으로 관리한다.(각각의 프로세스마다 CPU, 메모리 등이 별도로 할당됨)
  •                "              따라서 하나의 컴퓨터에서 여러 프로세스가 동시에 실행될 수 있다.(멀티태스킹) -> 병렬처리 가능.

단점

  • 각각의 프로세스에 메모리 할당 -> 메모리 사용량이 높다. -> 높은 자원 소비
  • 프로세스 간에 데이터를 공유하려면 통신이 복잡하고 느림 -> 성능상 오버헤드 발생할 수 있음.

 

스레드(Thread)란?

➡️ 프로세스 내에서 실행되는 작은 실행단위 (하나의 프로세스 내 여러 스레드 존재)

 

특징

  • 같은 데이터를 공유하므로 스레드간 통신이 빠르고 리소스(자원소비)를 적게 사용함

 

단점

  • 메모리를 공유하므로 동기화가 잘못되면 (Race Condition 경쟁 조건)이 발생 가능.
  • 하나의 스레드 오류로 전체 프로세스가 영향을 받을 수 있음.
  • 파이썬에서 GIL (Global Interpreter Lock) 이 존재하여 한 번에 하나의 쓰레드만 실행될 수 있는데 이 때문에 CPU 집약적인 작업에서는 멀티스레딩이 병렬 처리의 이점을 얻지 못함

 

✅ 쓰레드는 같은 메모리 공간을 공유한다는 말이 무엇인가?

→ 그래서 한 쓰레드가 어떤 데이터를 수정하고 있을 때, 다른 쓰레드도 동시에 그 데이터를 읽거나 쓸 수 있음을 뜻한다.

✅ 동기화(Synchronization)는 무엇인가?

→ 여러 쓰레드가 공유 자원(예: 리스트, 변수 등)에 동시에 접근하지 않도록 제한을 거는 행위이다.

✅ 경쟁 조건 (Race Condition)이란 무엇인가?

→ 두 개 이상의 쓰레드가 동시에 같은 자원에 접근하고, 그 중 적어도 하나가 데이터를 수정할 때 발생하는 문제이다.

     이 경쟁조건을 해결하기 위해서 동기화가 필요한 것이다. 파이썬의 경우는 threading.Lock() 같은 락(Lock)을 이용한다.

 동기화를 해야 하는데, 같은 선상에 있는 쓰레드가 경쟁을 일으킨다는 게 무슨 말인가?

같은 자원을 동시에 쓰려는 쓰레드들 사이에서 접근 타이밍이 겹치면 경쟁(race)이 발생한다.
그래서 동기화를 해야하는데 동기화는 한 번에 하나의 쓰레드만 자원에 접근하도록 "순서를 정해주는" 역할을 하는거다.

 

✅ 간단 정리

 

메모리 독립된 메모리 공간을 사용 메모리를 공유
자원 관리 독립적으로 자원 관리 프로세스 자원을 공유
병렬 처리 멀티코어에서 진정한 병렬 처리 가능 GIL 때문에 한 시점에 하나의 쓰레드만 실행 (CPU 작업에서 병렬 처리 제한)
속도 자원을 많이 사용하므로 상대적으로 느림 경량으로 빠름, 하지만 GIL에 의해 CPU 집약적인 작업에선 제한됨
통신 IPC(Inter-Process Communication)가 필요 메모리 공유를 통해 쉽게 통신 가능
안정성 다른 프로세스와 독립적이므로 안정성 높음 메모리 공유로 인해 동기화 문제 가능
자원 소비 높은 메모리 사용 낮은 메모리 사용

프로세스를 사용해야 할 경우:

  1. 여러 작업이 독립적으로 실행되어야 할 때
  2. CPU 집약적인 작업에서 멀티코어를 최대한 활용하고 싶을 때
  3. 안정성이 중요한 경우 (프로세스가 다른 프로세스에 영향을 미치지 않음)

🔹 CPU 집약적인 작업이란?

      예: 큰 수끼리 곱하기, 행렬 연산, 반복 루프 계산 등

🔹 멀티코어란?

     요즘 컴퓨터나 서버는 CPU가 여러 개의 코어를 가지고 있음

 

    예: 4코어, 8코어, 16코어…

  • 코어 1개 = 한 번에 1가지 작업 가능
  • 코어 4개 = 동시에 4개의 작업 수행 가능

🔹 CPU를 많이 쓰는 작업 = 수치 계산, 암호화, 이미지/영상 처리, 인공지능 연산 등

 

🔹 왜 멀티코어를 "최대한 활용"해야 할까?

     파이썬에서는 threading을 써도 GIL(Global Interpreter Lock) 때문에
      → 한 번에 하나의 스레드만 실행됨
      (즉, 여러 스레드를 만들어도 CPU는 실제로 하나만 씀)

그래서 "CPU 집약적 작업"에서는...

멀티스레딩은 효과가 없고,
멀티프로세싱이 필요하다!

 

멀티프로세싱을 쓰면, 각 프로세스는 GIL의 영향을 받지 않고,
→ 각자 독립적인 코어에서 실행할 수 있다.
→ 이게 바로 멀티코어를 최대한 활용하는 것이다.

 

쓰레드를 사용해야 할 경우:

  1. I/O 작업(파일 읽기/쓰기, 네트워크 요청 등)을 동시에 처리할 때
  2. 프로세스 간 통신이 필요 없고, 빠른 실행이 필요할 때
  3. 상대적으로 적은 메모리를 사용하는 애플리케이션을 만들고 싶을 때 

🔸 I/O 작업이란?

     →  Input/Output 작업, 즉 입출력 작업을 뜻한다 → 컴퓨터에서 "CPU 외부와 데이터를 주고받는 모든 작업"

      • I/O  작업 종류예시
        파일 I/O 파일 읽기/쓰기, 로그 저장 등
        네트워크 I/O 웹 API 요청, 소켓 통신, DB 요청 등
        디스크 I/O SSD/HDD로부터 데이터 읽기/쓰기
        사용자 입력 키보드 입력, 마우스 클릭 등 (GUI/CLI)

🔸 왜 I/O 작업이 문제인가?

CPU가 직접 계산하지 않고,
"외부 자원"과 데이터를 주고받는 작업이기 때문에 아래의 흐름으로 진행되어 느림

  1. CPU가 요청을 보냄
  2. 서버에서 응답이 올 때까지 "기다려야" 함
  3. 응답이 오면 다음 코드로 넘어감

이 기다리는 동안 → CPU는 놀고 있음 😴
→ 이런 걸 블로킹(blocking)이라하는데 이를 방지하기 위해서

 

멀티스레딩 or 비동기(asyncio)를 사용!