-
[Python] GIL(Global interpreter Lock) 이해하기코딩/파이썬 2023. 7. 29. 23:08반응형
Python 에서는 멀티스레드를 사용하려다 보면, GIL(Global interpreter Lock)에 대해 많이 듣게 됩니다. GIL은 인터프리터 언어인 python의 특성으로 이를 이해해야 효율적인 멀티스레드 코드를 작성할 수 있습니다. 이번에는 GIL의 개념에 대해서 알아 보도록 하겠습니다.
목차
1. GIL(Global interpreter Lock)이란?
1. GIL(Global interpreter Lock)이란?
GIL, 즉 글로벌 인터프리터 락(Global Interpreter Lock)은 Python의 중요한 메모리 관리 요소입니다. 이것은 이름에서 알 수 있듯이 인터프리터 자체에 걸린 'Lock(잠김)'의 개념으로 이해할 수 있습니다.
쉽게 말해, GIL은 한 번에 하나의 스레드만 Python 객체에 접근하게 해주는 메커니즘입니다. GIL로 인해 Python의 멀티스레딩은 실제로는 동시에 실행되지 않고, 하나의 스레드가 실행 완료된 후에 다음 스레드가 실행됩니다. 개념적으로, 아래의 이미지와 같습니다.특정 환경에서는 멀티 스레드일 경우, 스위칭 비용 때문에 시간이 더 소요될 수 있습니다. 어떤 의미에서, 파이썬의 멀티스레드는 진정한 멀티가 아닌 셈이죠.
2. GIL이 왜 필요한가?
처음 python을 공부할 때, GIL 개념을 접하고 어이가 없었습니다. 다중 실행을 못하는데, 도데체 왜 GIL 개념을 도입한걸까요?
python wiki에 보면 아래와 같이 설명되어 있습니다.
In CPython, the global interpreter lock, or GIL, is a mutex that protects access to Python objects, preventing multiple threads from executing Python bytecodes at once. The GIL prevents race conditions and ensures thread safety. A nice explanation of how the Python GIL helps in these areas can be found here.
....
In short, this mutex is necessary mainly because CPython's memory management is not thread-safe.
CPython에서 글로벌 인터프리터 잠금(GIL)은 파이썬 객체에 대한 액세스를 보호하는 뮤텍스이며, 여러 스레드가 한 번에 파이썬 바이트코드를 실행하는 것을 방지합니다. GIL은 경쟁 조건을 방지하고 스레드 안전을 보장합니다.
....
요컨대, 이 뮤텍스는 주로 CPython의 메모리 관리가 스레드 안전하지 않기 때문에 필요합니다.https://wiki.python.org/moin/GlobalInterpreterLock
즉, GIL 도입은 Python에서의 메모리 관리 방식과 관계가 깊습니다.
Python은 참조 계수(reference count) 방식을 이용하여 객체의 메모리를 관리합니다. Python은 모든 것이 객체입니다. 이 객체는 객체가 참조된 횟수를 가지고 있습니다. 이를 reference count라고 하는데요. Python에서는 이 참조 계수(reference count)가 0이되면, 안 쓰는 객체로 판단하여 객체를 지우는 작업을 합니다. 간단한 구현 방식이죠
그런데 멀티스레딩을 하면 이런 구현 방식에 문제가 발생하게 됩니다. 아래 예시에서, 만약 Thread 1과 Thread 2가 거의 동시에 실행된다면, obj의 참조 카운트가 증가하기 전에 감소하거나, 또는 감소하기 전에 증가하는 등의 상황이 발생할 수 있습니다. 이러한 동시 수정은 참조 카운트의 정확성을 해치고, 이로 인해 메모리 누수 등의 문제가 발생할 수 있습니다.
# 객체 생성 some_list = [] # Thread 1 some_list.append(obj) # obj의 참조 카운트를 증가시킴 # Thread 2 some_list.remove(obj) # obj의 참조 카운트를 감소시킴
여러 스레드에서 하나의 객체를 바라본다면,
참조 계수 관리가 어렵고 비효율이 발생하기 때문에, GIL로 전체 잠김 처리를 합니다.
3. 파이썬의 멀티스레딩은 항상 느린가?
결론부터 말하면, 그렇지 않습니다. Python에서의 멀티스레딩은 CPU 바운드 작업에 대해서는 GIL로 인해 병렬 처리의 이점을 제대로 활용하지 못하지만, I/O 바운드 작업에 대해서는 매우 효율적입니다. I/O 바운드 작업에서는 대부분의 시간이 대기 시간으로 소비되기 때문에, 다른 스레드가 실행되는 동안 해당 대기 시간을 활용할 수 있습니다.
따라서, Python의 멀티스레딩은 CPU 바운드 작업에 대해선 한계가 있지만, I/O 바운드 작업에서는 여전히 효율적인 방법으로 사용될 수 있습니다.가령 아래와 같이 웹에서 어떤 정보를 다운로드 받는데, 멀티 쓰레드를 사용한다면 매우 효과적일 것입니다.
import threading import requests import time def download_site(url): response = requests.get(url) content = response.content start_time = time.time() threads = [] for _ in range(100): thread = threading.Thread(target=download_site, args=("https://www.example.com",)) thread.start() threads.append(thread) for thread in threads: thread.join() end_time = time.time() print("Time taken:", end_time - start_time)
Python의 GIL에 대해 이해하는 것은 Python을 사용하여 동시성 문제를 다루는 데 중요한 첫걸음입니다. 이를 이해함으로써 어떤 유형의 작업에 멀티스레딩을 적용해야 하는지, 그리고 이를 어떻게 최적화할 수 있는지에 대한 깊은 이해를 얻을 수 있습니다.
https://smart-worker.tistory.com/50
https://smart-worker.tistory.com/49
https://smart-worker.tistory.com/47
반응형'코딩 > 파이썬' 카테고리의 다른 글
[Python] JSON 데이터 손쉽게 다루기 (0) 2023.07.30 [Python] 텍스트 파일 읽고 쓰기(open, readlines 등) (0) 2023.07.30 [Python]람다(lambda) 함수 이해하기 (0) 2023.07.29 [Python] 리스트와 튜플(tuple)의 차이점 이해하기 (0) 2023.07.29 [Python] 초보자를 위한 데코레이터(Decorator) 사용법 (0) 2023.07.29