인터프리터 언어(Interpreter Language)
파이썬은 기본적으로 인터프리터 언어이다. 고급 프로그래밍 언어의 대부분인 70% 이상이 인터프리터 언어라고 할 수 있다. 대표적인 웹 인터프리터 언어인 JavaScript부터 SQL, Ruby, MATLAB 등이 있다.
컴파일 언어(Compiled Language)와 다르게 인터프리터 언어는 언어를 설계하는 기간이 엄청나게 단축된다. 컴파일러를 인터프리터 언어로 구현할 필요가 없기 때문이다.
또한 프로그램을 수정하는 시간도 적게 걸린다. 인터프리터 언어는 한번에 모든 코드를 컴파일 하지 않고, 각각의 코드들을 한줄씩 기계어로 번역하고 동시에 실행하기 때문에, 빠르고 쉽게 수정해 가면서 개발을 진행 할 수 있다.
인터프리터 언어는 싱글 스레드에서 순차적으로 동작하기 때문에 속도가 느려진다는 절대적인 단점이 있지만, 메모리 처리의 안정성을 쉽게 보장할 수 있다. 멀티 스레드에서 자주 발생하는 Reference Counting에 의한 메모리 누수 및 메모리 낭비 등을 보다 쉬운 방법으로 예방할 수 있다.
참조 횟수 계산 방식 - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. 참조 횟수 계산 방식(reference counting)은 메모리를 제어하는 방법 중 하나로, 쓰레기 수집의 한 방식이다. 구성 방식은 단순하다. 어떤 한 동적 단위(객체, Object)가
ko.wikipedia.org
파이썬의 금제 GIL(Global Interpreter Lock)
파이썬은 여러개의 스레드를 사용하더라도, 파이썬 바이트 코드를 한번에 하나씩만 사용할 수 있게 전역적으로 락을 걸어 놓는다.
즉, 파이썬의 스레드는 메모리의 안정적인 관리를 위해서 오직 하나의 스레드만이 파이썬 객체에 접근할 수 있도록 제한하는 락(Lock), 뮤텍스(Mutex)를 설정하는데 이를 GIL(Global Interpreter Lock)이라 한다.
이를 통해서 Garbage Collection같은 메모리 관리는 쉽고 안전하게 구현할 수 있지만, 최신 언어들에서 필수적으로 여겨지는 멀티 코어, 멀티 스레드를 사용한 병렬 처리가 잘 이루어지지 않는다.
파이썬에서 멀티 스레드를 적용해서 연산 작업을 나누어 실행하는 경우에는 오히려 계산 속도가 더 느려지는 것을 발견 할 수 있다. 이렇게 파이썬을 사용한 멀티 스레드 프로그램에서는 싱글 스레드처럼 동작하는 병목 현상이 나타난다. 이를 여러 개발자 커뮤니티에서는 GIL의 과도한 성능제한에 대해서 악랄하다고 한다…!
https://grouplens.org/blog/pythons-gil-is-evil/
Python’s GIL is EVIL
Lately I’ve been doing some Python multi-threading to make the best use of some of our amazing server resources. As I was pondering the reasons why one of our 8-core servers reported 83% idle…
grouplens.org
다만, I/O작업은 메모리를 사용하지 않기 때문에 GIL의 제한을 받지 않는다. 그래서 I/O 작업을 수행하는 동안 추가적인 스레드를 사용해서 I/O 작업과 CPU 동작을 동시에 멀티로 진행할 수 있다. 따라서 파이썬에서의 효율적인 멀티 스레드 사용은 I/O 작업이 많이 있을 때 이루어 질 수 있다. I/O 작업이 많은 네트워크 통신, 파일 read,write 같은 상황에서 파이썬은 멀티 스레드를 사용해서 효율적으로 작업을 할 수 있다.
멀티 프로세스(Multi Process)
이런 병렬적인 처리에 대한 파이썬의 문제점을 해결하기 위해서 많은 Python 개발자들은 멀티 스레드가 아닌 멀티 프로세스(Multi Process)를 사용해서 병렬적으로 코드를 진행한다.
멀티 스레드(Multi Thread)는 메모리를 공유하고, 소프트웨어적으로 나누어서 병렬적으로 실행하지만,
멀티 프로세스는(Multi Process) 하드웨어적으로 나누어져 있기 때문에, 메모리를 별도로 사용한다.
메모리를 분리해서 사용하기 때문에 GIL이 적용되지 않아서 더 효율적으로 분리해서 진행할 수 있지만, 하드웨어적으로 분리되기 때문에 복잡성이 높아지고, 오버헤드(Overhead) 발생이 더 많아질 수 있다.
<멀티 스레드 예시>
import threading
def print_numbers():
for i in range(5):
print(i)
threads = [threading.Thread(target=print_numbers) for _ in range(2)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
병렬적으로 스레드를 나누어 실행해도 GIL 이 제한하기 때문에 순차적으로 처리된다.
0
1
2
3
4
0
1
2
3
4
<멀티 프로세스 예시>
from multiprocessing import Process
def print_numbers():
for i in range(5):
print(i)
processes = [Process(target=print_numbers) for _ in range(2)]
for process in processes:
process.start()
for process in processes:
process.join()
병렬적으로 나누어져서 따로 처리된다.
0
01
1
22
3
3
44
향후 파이썬의 병렬 처리
GIL을 사용함으로써 파이썬은 메모리의 안정성을 보장하고 메모리 관리를 단순화 한다. 또한, 이를 통해서 복잡한 lock 과정을 생략하고, 객체 관리를 효율적으로 진행하면서 싱글 스레드 성능을 압도적으로 높일 수 있었다.
하지만 매우 빠르게, 새롭게 변해가는 프로그래밍 언어의 세계에서 현재 멀티 스레드 같은 병렬 처리 방식은 너무 당연하게 여겨지고 있다.
파이썬은 병렬처리에 대한 단점에 비해서 너무나 많은 장점들이 존재하기 때문에 2024년 기준 가장 많이 사용되는 프로그래밍 언어이며, 많은 곳에서 사용되고 있기 때문에
👑Python은 2024년 최고의 프로그래밍 언어로 선정되었다.👑
하지만 최고의 타이틀을 유지하고 더 앞으로 다음 단계로 나아가기 위해서는 병렬 처리에 대한 문제를 해결해야 한다고 생각한다. 이에 맞춰서 많은 파이썬 커뮤니티에서는 악랄한 GIL을 제거(?)하기 위해서 많은 개발자들이 머리를 싸매고 연구하고, 도전하고 있다!
'Python' 카테고리의 다른 글
[Python] __name__ 부터 if __name__ == “__main__” : 까지 완벽 정리 (2) | 2025.02.05 |
---|---|
[Python] 피클(pickle) 파일 (5) | 2025.02.03 |
[Python] 멀티 쓰레드의 확장(Python 3.13, CPython, no-GIL 설정) (10) | 2024.12.20 |