[Python] Global Interpreter Lock, CUDA
1. GIL이란?
- python 인터프리터가 동시에 하나의 스레드만 실행하도록 제한하는 락
- 단일 바이트코드 실행 중엔 다른 스레드가 끼어들지 못함
=> 복잡한 여러 바이트코드 작업(예: 리스트 두번 접근)은 중간에 끼어들 수 있다 => threading.Lock으로 보호
=> 멀티스레드를 써도 한 번에 하나의 스레드만 실행된다
=> 동시에 여러 CPU 코어를 못쓴다 => 병렬 처리에 제한이 있다.
# threading.Lock 없으면
# GIL만 있고 Lock 없이 공유 변수 접근
counter = 0
def add():
global counter
for _ in range(100000):
counter += 1 # 읽고 → 계산 → 쓰는 사이에 다른 스레드가 끼어들 수 있음!
threads = []
for _ in range(2):
t = threading.Thread(target=add)
threads.append(t)
t.start()
for t in threads:
t.join()
print(counter) # 기대값: 200000 → 실제론 19xxxx 나올 수도 있음
----------------------------------------------------------------------------------------
# threading.Lock적용
lock = threading.Lock()
def add():
global counter
for _ in range(100000):
with lock:
counter += 1 # 여기서는 한 스레드가 끝날 때까지 다른 애가 못 끼어듦
* GIL은 파이썬 인터프리터 수준에서만 순서를 제어할 뿐, 실제로동시성 문제를 막기 위해서는 threading.Lock()이 필요
2. 왜 필요할까?(장점)
- 스레드 간 데이터 충돌을 막기 위해서
- 예: 동시에 하나의 값을 수정하면 꼬임이 발생(동시에 리스트에 값 추가하면 하나만 추가되거나 에러)
- GIL로 잠궈놓고 하나씩 처리하면 버그 없이 안전하게 실행된다
3. 문제점(단점)
- CPU 계산이 많은 작업(영상처리, 수학 계산 등)이 GIL 때문에 병렬처리가 안되 성능이 저하된다
- I/O 작업 위주(파일 읽기, 웹 요청 등): Sleep, wait 중에는 GIL이 풀려서 멀티스레드 효과가 있다.
4. 해결방법
- 멀티프로세싱을 사용한다 => GIL 안 걸림
- 다른 언어로 병렬 처리(C, Rust 등 확장)
- python 대안 => Jython, IronPython 사용
5. 스레드간 자원 교환이 가능할까?
- python에서 스레드 간 메모리가 공유된다.(자원 교환이 가능하다)
=> 동시에 접근할 경우 데이터 충돌이 일어나기 때문에 락으로 제어해야 한다.
- 스레드는 프로세스 내에서 돌아가기 때문에 같은 변수, 리스트, 객체에 접근이 가능하다.
6. 프로세스간 자원교환이 가능할까?
- 스레드는 같은 메모리 공간을 공유하지만, 프로세스는 서로 완전히 분리되어 있어 자원(전역변수 등) 공유가 불가능하다
- 공유하고싶다면? python 내장 표준 라이브러리인 multiprocessing 사용
7. 그럼 왜 GIL로 성능이 저하되는 python을 AI에 쓸까?
- python은 쉬운 문법으로 복잡한 계산을 지시하는 인터페이스일뿐, 실제 계산은 대부분 GIL이 없는 외부 라이브러리에서 병렬 처리 된다.
분야 | python에서 쓰는 라이브러리 | 실제 연산 처리 |
AI/딥러닝 | Tensorflow, Pytorch | C++, CUDA |
수학계산 | Numpy | C |
머신러닝 | scikit-learn | Cython, C |
행렬연산 | Pandas, Numpy | 내부는 대부분 C기반 |
GPU 사용 | Pytorch, .cuda() | CUDA(GPU언어) |
8. CUDA란?
- Compute Unified Device Architecture
- NVIDIA가 만든 GPU(그래픽카드)용 병렬 계산 프로그래밍 기술(C++기반 언어로 작성)
- PyTorch나 TensorFlow의 .cuda()를 쓰면 내부적으로 CUDA C/C++를 호출해줌
- GPU를 CPU처럼 코딩해서 계산에 활용할 수 있게 해주는 기술
* GPU: 수천 개의 코어로 동시에 수학 계산을 해서 AI나 딥러닝 같이 행렬 연산이 많은 작업에 적합
import torch
x = torch.tensor([1.0, 2.0, 3.0])
x = x.cuda() # GPU 메모리로 이동시킴