Global Interpreter Lock이 필요한 이유


89

Python의 Global Interpreter Lock의 기능은 정확히 무엇입니까? 바이트 코드로 컴파일 된 다른 언어도 비슷한 메커니즘을 사용합니까?


6
"중요한가?"라고 물어봐야합니다.
S.Lott

2
동의합니다. 이제 2.6에서는 다중 처리 모듈이 추가되어 스레드와 같은 방식으로 여러 프로세스를 사용하여 프로그래밍 할 수있게되었으므로 문제가되지 않는다고 생각합니다. docs.python.org/library/multiprocessing.html
monkut

답변:


69

일반적으로 스레드 안전 문제에 대해 내부 데이터 구조를 잠금으로 보호해야합니다. 이는 다양한 수준의 세분화로 수행 할 수 있습니다.

  • 모든 개별 구조에 자체 잠금이있는 세분화 된 잠금을 사용할 수 있습니다.

  • 하나의 잠금이 모든 것을 보호하는 거친 잠금을 사용할 수 있습니다 (GIL 접근 방식).

각 방법에는 다양한 장단점이 있습니다. 세분화 된 잠금은 더 큰 병렬 처리를 허용합니다. 두 스레드는 리소스를 공유하지 않을 때 병렬로 실행할 수 있습니다. 그러나 훨씬 더 큰 관리 오버 헤드가 있습니다. 모든 코드 행에 대해 여러 잠금을 획득하고 해제해야 할 수 있습니다.

대략적인 접근 방식은 그 반대입니다. 두 개의 스레드는 동시에 실행할 수 없지만 개별 스레드는 많은 부기 작업을 수행하지 않기 때문에 더 빠르게 실행됩니다. 궁극적으로 단일 스레드 속도와 병렬 처리 사이의 절충안으로 귀결됩니다.

파이썬에서 GIL을 제거하려는 시도가 몇 번 있었지만 단일 스레드 머신의 추가 오버 헤드는 일반적으로 너무 큽니다. 일부 경우에는 잠금 경합으로 인해 다중 프로세서 시스템에서도 실제로 더 느릴 수 있습니다.

바이트 코드로 컴파일 된 다른 언어도 비슷한 메커니즘을 사용합니까?

그것은 다양하며 아마도 구현 속성만큼 언어 속성으로 간주되어서는 안됩니다. 예를 들어, GIL 접근 방식이 아닌 기본 VM의 스레딩 접근 방식을 사용하는 Jython 및 IronPython과 같은 Python 구현이 있습니다. 또한 다음 버전의 Ruby는 GIL 도입하는 방향으로 나아가고 있습니다 .


1
이것을 설명 할 수 있습니까 : '두 개의 스레드가 동시에 실행할 수 없습니다'? 최근에 저는 멀티 스레딩을 사용하여 Python으로 간단한 웹 서버를 작성했습니다. 클라이언트의 모든 새로운 요청에 대해 서버는 새로운 스레드를 생성하고 해당 스레드는 계속 실행됩니다. 따라서 동시에 여러 스레드가 실행될 것입니다. 아니면 잘못된 방식으로 이해 했습니까?
AVI

1
@avi AFAIK python 스레드는 동시에 실행할 수 없지만 한 스레드가 다른 스레드를 차단해야한다는 의미는 아닙니다. GIL은 한 번에 하나의 스레드 만 파이썬 코드를 해석 할 수 있음을 의미 할뿐 스레드 관리 및 리소스 할당이 작동하지 않는다는 의미는 아닙니다.
Benproductions1 2014

2
^ 따라서 언제든지 하나의 스레드 만 클라이언트에 콘텐츠를 제공하므로 성능 향상을 위해 실제로 멀티 스레딩을 사용할 필요가 없습니다. 권리?
avi

물론 Java는 바이트 코드로 컴파일되며 매우 세밀한 잠금을 허용합니다.
Warren Dew 2014

3
@avi, 웹 서버와 같은 IO 바인딩 프로세스는 여전히 Python 스레드에서 얻을 수 있습니다. 둘 이상의 스레드가 동시에 IO를 수행 할 수 있습니다. 동시에 해석 (CPU) 할 수 없습니다.
Saish 2015-04-15

33

다음은 공식 Python / C API 참조 설명서에서 발췌 한 것입니다 .

Python 인터프리터는 스레드로부터 완전히 안전하지 않습니다. 다중 스레드 Python 프로그램을 지원하기 위해 Python 객체에 안전하게 액세스하려면 현재 스레드가 보유해야하는 전역 잠금이 있습니다. 잠금이 없으면 가장 간단한 작업도 다중 스레드 프로그램에서 문제를 일으킬 수 있습니다. 예를 들어 두 스레드가 동시에 동일한 객체의 참조 카운트를 증가 시키면 참조 카운트가 두 번이 아닌 한 번만 증가 할 수 있습니다.

따라서 전역 인터프리터 잠금을 획득 한 스레드 만 Python 객체에서 작동하거나 Python / C API 함수를 호출 할 수 있다는 규칙이 있습니다. 다중 스레드 Python 프로그램을 지원하기 위해 인터프리터는 정기적으로 잠금을 해제하고 다시 획득합니다. 기본적으로 100 바이트 코드 명령마다 (sys.setcheckinterval ()으로 변경할 수 있습니다). 잠금이 해제되고 파일 읽기 또는 쓰기와 같은 잠재적으로 차단되는 I / O 작업을 중심으로 다시 획득되므로 I / O를 요청하는 스레드가 I / O 작업이 완료되기를 기다리는 동안 다른 스레드가 실행될 수 있습니다.

나는 그것이 문제를 꽤 잘 요약한다고 생각합니다.


1
나도 읽었지만 파이썬이 자바 (
그렇지

@EliBendersky 파이썬 스레드의 pthreads로 구현하고 OS (의해 처리 dabeaz.com/python/UnderstandingGIL.pdf 자바 쓰레드는 애플리케이션 레벨 스레드를 whos 스케줄링은 JVM에서 처리되는 반면)
gokul_uf

19

글로벌 인터프리터 잠금은 참조 카운터가 호스에 걸리지 않도록 보호하는 큰 뮤텍스 유형 잠금입니다. 순수 파이썬 코드를 작성하는 경우이 모든 작업은 백그라운드에서 발생하지만 Python을 C에 포함하는 경우 명시 적으로 잠금을 해제 / 해제해야 할 수 있습니다.

이 메커니즘은 파이썬이 바이트 코드로 컴파일되는 것과 관련이 없습니다. Java에는 필요하지 않습니다. 사실, Jython (python은 jvm으로 컴파일 됨) 에도 필요하지 않습니다 .

이 질문 도 참조


4
"이 메커니즘은 파이썬이 바이트 코드로 컴파일되는 것과 관련이 없습니다.": 정확하게는 CPython 구현의 아티팩트입니다. 스레드 안전 구현 덕분에 다른 구현 (예 : Jython)은 이러한 제한
벗어날 수 있습니다.

11

Perl 5와 마찬가지로 Python은 처음부터 스레드로부터 안전하도록 설계되지 않았습니다. 스레드는 사후에 접목되었으므로 글로벌 인터프리터 잠금은 인터프리터의 장에서 주어진 시간에 하나의 스레드 만 코드를 실행하는 위치에 대한 상호 배제를 유지하는 데 사용됩니다.

개별 Python 스레드는 자주 잠금을 순환하여 인터프리터 자체가 협력 적으로 멀티 태스킹합니다.

다른 파이썬 스레드가이 프로토콜을 '옵트 인'하고 뒤에서 안전하지 않은 일이 발생하지 않도록 활성 상태 일 때 C에서 Python과 대화 할 때 잠금을 직접 잡아야합니다.

나중에 다중 스레드 시스템으로 발전한 단일 스레드 유산을 가진 다른 시스템에는 종종 이러한 종류의 메커니즘이 있습니다. 예를 들어, Linux 커널에는 초기 SMP 시절부터 "Big Kernel Lock"이 있습니다. 점차적으로 멀티 스레딩 성능이 문제가됨에 따라 이러한 종류의 잠금을 더 작은 조각으로 나누거나 처리량을 최대화하기 위해 가능한 경우 잠금없는 알고리즘 및 데이터 구조로 교체하려는 경향이 있습니다.


대부분의 생각보다 거친 잠금이 사용된다는 사실, 특히 자주 잊혀진 BKL (내가 사용 reiserfs하는 유일한 실제 이유) 을 언급 한 경우 +1 .
new123456 2011-07-07

3
Linux에는 BKL이 있었으며 버전 2.6.39부터 BKL이 완전히 제거되었습니다.
avi

5
물론이야. 내가 질문에 답한 지 약 3 년이 지난 당신을 기억하십시오. =)
Edward KMETT

7

두 번째 질문과 관련하여 모든 스크립팅 언어가 이것을 사용하는 것은 아니지만 덜 강력하게 만듭니다. 예를 들어 Ruby의 스레드는 기본이 아닌 녹색 입니다.

Python에서 스레드는 기본이며 GIL은 스레드가 다른 코어에서 실행되는 것을 방지합니다.

Perl에서는 스레드가 훨씬 더 나쁩니다. 그들은 단지 전체 인터프리터를 복사 할 뿐이며 파이썬 에서처럼 유용하지 않습니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.