development

Global Interpreter Lock이 필요한 이유

big-blog 2020. 9. 16. 08:08
반응형

Global Interpreter Lock이 필요한 이유


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


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

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

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

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

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

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

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

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


다음은 공식 Python / C API 참조 설명서 에서 가져온 것입니다 .

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

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

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


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

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

이 질문 도 참조


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

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

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

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


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

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

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


어쩌면 BDFL에 의해 기사는 도움이 될 것입니다.

참고 URL : https://stackoverflow.com/questions/265687/why-the-global-interpreter-lock

반응형