글로벌 인터프리터 잠금 (GIL)이 Python에서 스레딩 등이 까다로운 문제인 주요 이유로 자주 인용되는 것 같습니다. “처음에 왜 그렇게 되었습니까?”
프로그래머가 아니기 때문에 그 이유가 무엇인지 모르겠습니다. GIL을 넣는 논리가 무엇 이었습니까?
댓글
- Wikipedia 기사 에는 " GIL은 병렬 처리에 대한 중요한 장벽이 될 수 있습니다. 즉, 언어의 역 동성을 갖는 대가를 지불하고 " 계속해서 " 이러한 잠금을 사용하는 이유는 다음과 같습니다. 단일 스레드 프로그램의 속도 증가 (모든 데이터 구조에 대한 잠금을 개별적으로 획득하거나 해제 할 필요 없음), 일반적으로 사용되는 C 라이브러리의 손쉬운 통합 스레드로부터 안전하지 않습니다. "
- @RobertHarvey, Dynamism은 할 일이 없습니다. 그것으로. 문제는 돌연변이입니다.
- stackoverflow.com/questions/265687/ …
- 자바 '에 부호없는 숫자가 부족한 것처럼 ' 도움이되지 않습니다. ' ' 자신이 발을 쏘고 있는지 모릅니다. 불행히도, 자신이 무엇을하는지 만족 하는 사람은 ' 불완전한 언어를 얻습니다. 이는 Python이 다른 많은 방식으로 흔들 리기 때문에 정말 부끄러운 일입니다.
- @Basic 암호화 수학을 수행하려면 Java에서 바이트 배열을 처리 할 수있는 표준 방법이 있어야합니다 (' 오랜 시간 동안 사용하지 않았습니다). 예를 들어 Python은 ' 부호있는 숫자가 없지만 '는 비트 단위 연산을 시도하지 않습니다. 더 나은 방법입니다.
Answer
Python, IronPython, RPython, 등
일부는 GIL이 있고 일부는 GIL이 없습니다. 예를 들어 CPython에는 GIL이 있습니다.
From http://en.wikipedia.org/wiki/Global_Interpreter_Lock
GIL을 사용하여 프로그래밍 언어로 작성된 애플리케이션은 별도의 프로세스를 사용하여 완전한 병렬 처리를 달성하도록 설계 할 수 있습니다. 각 프로세스에는 자체 인터프리터와 차례로 자체 GIL이 있습니다.
GIL의 이점
- 단일 스레드 프로그램의 속도 향상
- 일반적으로 스레드로부터 안전하지 않은 C 라이브러리의 손쉬운 통합
Python (CPython 및 기타)이 GIL을 사용하는 이유
CPython에서 전역 인터프리터 잠금 또는 GIL은 여러 원시 스레드가 한 번에 Python 바이트 코드를 실행하지 못하도록 방지하는 뮤텍스입니다. 이 잠금은 주로 CPython의 메모리 관리가 스레드로부터 안전하지 않기 때문에 필요합니다.
GIL은 특정 상황에서 다중 스레드 CPython 프로그램이 다중 프로세서 시스템을 최대한 활용하지 못하도록 막기 때문에 논란의 여지가 있습니다. I / O, 이미지 처리 및 NumPy 번호 처리와 같은 장기 실행 작업은 GIL 외부에서 발생합니다. 따라서 GIL 내부에서 CPython 바이트 코드를 해석하는 데 많은 시간을 소비하는 다중 스레드 프로그램에서만 GIL이 병목 현상.
Python은 여러 가지 이유로 세분화 된 잠금과 달리 GIL을 사용합니다.
-
단일 스레드의 경우 더 빠릅니다.
-
i / o 바인딩 된 프로그램의 경우 다중 스레드의 경우 더 빠릅니다.
-
cpu 바인딩 된 프로그램의 경우 다중 스레드의 경우 더 빠릅니다. C 라이브러리에서 계산 집약적 인 작업을 수행합니다.
-
작성하기 쉬운 C 확장 : 허용되는 위치를 제외하고는 Python 스레드의 전환이 없습니다 (예 : Py_BEGIN_ALLOW_THREADS 매크로와 Py_END_ALLOW_THREADS 매크로 사이).
-
C 라이브러리를 더 쉽게 래핑 할 수 있습니다. 스레드 안전성에 대해 걱정할 필요가 없습니다. 라이브러리가 스레드로부터 안전하지 않으면 GIL을 호출하는 동안 잠금 상태를 유지하기 만하면됩니다.
GIL은 Python의 표준 라이브러리는 각 블로킹 I / O 호출에 대해 GIL을 릴리스합니다. 따라서 GIL은 I / O 바운드 서버의 성능에 영향을 미치지 않습니다. 따라서 프로세스 (포크), 스레드 또는 비동기 I / O를 사용하여 Python에서 네트워킹 서버를 만들 수 있으며 GIL은 방해가되지 않습니다.
C 또는 Fortran의 숫자 라이브러리는 GIL이 출시되었습니다. C 확장이 FFT가 완료되기를 기다리는 동안 인터프리터는 다른 Python 스레드를 실행합니다.따라서 GIL은이 경우에도 세분화 된 잠금보다 쉽고 빠릅니다. 이것은 수치 작업의 대부분을 구성합니다. NumPy 확장은 가능할 때마다 GIL을 릴리스합니다.
스레드는 일반적으로 대부분의 서버 프로그램을 작성하는 잘못된 방법입니다. 부하가 낮 으면 포크가 더 쉽습니다. 부하가 높으면 비동기 I / O 및 이벤트 기반 프로그래밍 (예 : Python의 Twisted 프레임 워크 사용)이 더 좋습니다. 스레드를 사용하는 유일한 변명은 Windows에서 os.fork가 부족하다는 것입니다.
GIL은 순수 Python에서 CPU 집약적 인 작업을 수행하는 경우에만 문제가됩니다. 여기에서 프로세스와 메시지 전달 (예 : mpi4py)을 사용하여 깔끔한 디자인을 얻을 수 있습니다. Python cheese에는 “processing”모듈도 있습니다. 스레드와 동일한 인터페이스를 프로세스에 제공합니다 (예 : threading.Thread를 processing.Process로 대체).
스레드는 GIL에 관계없이 GUI의 응답 성을 유지하는 데 사용할 수 있습니다. GIL이 성능을 저하시키는 경우 (위의 논의 참조) 스레드가 프로세스를 생성하고 완료 될 때까지 기다릴 수 있습니다.
댓글
- 새콤한 포도 같은 소리 파이썬은 ' 스레드를 제대로 수행 할 수 없으므로 스레드가 불필요하거나 심지어 나쁜 이유를 구성합니다. " 낮다, fo rking이 더 쉽습니다 ", 정말로 요? 그리고 GIL은 참조 계산 GC 사용을 고집하는 경우에만 이러한 모든 경우에 대해 " 더 빠릅니다 ".
-
s/RPython/PyPy/g
. @MichaelBorgwardt 이유 제공 pro GIL이 문제의 핵심입니다. ' 그렇죠? 이 답변의 일부 내용 (즉, 대안에 대한 논의)이 요점을 벗어난 것에 동의합니다. 그리고 좋든 나쁘 든, refcounting은 이제 제거하기 거의 불가능합니다. 전체 API와 코드베이스에 깊이 뿌리 박혀 있습니다. ' 코드 절반을 다시 작성하고 모든 외부 코드를 깨뜨리지 않고서는 제거하는 것이 거의 불가능합니다. - Don '
multiprocessing
라이브러리 (2.6 이후 표준)를 잊지 마세요. '의 작업자 풀은 몇 가지 단순한 유형의 병렬 처리를위한 매우 매끄러운 추상화입니다. - @alcalde 다음을 수행하는 경우에만 ' 현재 수행중인 작업을 ' 모르거나 ' 스레드가 협력 적으로 작동하는 것을 원하지 않습니다 ./ 소통하다. 그렇지 않으면 ' 특히 일부 OS에서 새 프로세스를 시작하는 오버 헤드를 고려할 때 뒷면의 왕실 고통입니다. 코어가 32 개인 서버가 있으므로 CPython I '에서이를 완전히 활용하려면 32 개의 프로세스가 필요합니다. ' " 좋은 솔루션이 아닙니다 " ' CPython '의 부적절 함을 해결하기위한 해킹입니다.
- 스레드가 Windows 이외의 플랫폼에 존재한다는 사실은 forking이 ' 모든 상황에 적합하지 않습니다.
답변
먼저 off : Python에는 GIL이 없습니다. Python은 프로그래밍 언어입니다. 프로그래밍 언어는 추상적 인 수학적 규칙 및 제한의 집합입니다. Python 언어 사양에는 GIL이 있어야한다고 말하는 것은 없습니다.
Python의 구현에는 여러 가지가 있습니다. 일부는 GIL이 있고 일부는 그렇지 않습니다.
GIL을 갖는 것에 대한 간단한 설명 중 하나는 동시 코드 작성이 어렵다는 것입니다. 코드 주위에 거대한 잠금 장치를 배치하여 항상 직렬로 실행되도록합니다. 문제가 해결되었습니다!
특히 CPython에서 한 가지 중요한 목표는 C로 작성된 플러그인으로 인터프리터를 쉽게 확장 할 수 있도록하는 것입니다. 다시 말하지만 동시 코드를 작성하는 것은 어렵습니다. 동시성을 통해 인터프리터에 대한 확장을 작성하기가 더 쉽습니다. 또한 이러한 확장의 대부분은 동시성을 염두에두고 작성되지 않은 기존 라이브러리를 둘러싼 얇은 래퍼 일뿐입니다.
댓글
- 그 '는 Java '의 부호없는 숫자 유형 부족과 동일한 인수입니다. 개발자는 다른 모든 사람이 자신보다 멍청하다고 생각합니다 …
- @Basic-믿거 나 말거나, ' 정말, 정말 멍청하지 않더라도, 가정을 단순화하는 언어가 있다는 것이 밝혀졌습니다. ' 특정 사항을 작동시키기 위해 생각하지 않는 것은 여전히 유용합니다.CPython은 간단한 다중 스레드 응용 프로그램 (프로그램이 IO 바인딩되어 있고 많은 경우 GIL이 중요하지 않음)을 포함한 특정 작업에 적합합니다. GIL은 최상의 솔루션으로 이러한 응용 프로그램을보다 쉽게 프로그래밍 할 수 있습니다. 특히 컬렉션에 대한 원자 연산 을 지원한다는 사실이 있습니다.
- @Jules 예, it '는 이러한 기능이 필요할 때까지 매우 편리합니다. cpython ' s " 선호 " " C ++와 같은 다른 언어로 작성하면 " 단일 Python 혜택을 모두 잃게됩니다. ' 코드의 절반을 C ++로 작성한다면 왜 Python에서 시작해야할까요? 물론, 소규모 API / 글루 프로젝트의 경우 ' 빠르고 쉽고 ETL의 경우 ' 누구에게도 뒤지지 않지만 ' div id = “765eabeb7e”>
는 무거운 물건을 들어야하는 작업에는 적합하지 않습니다. 하드웨어와 통신하기 위해 Java를 사용하는 것과 동일합니다. ' 뛰어 넘어야하는 거의 코믹한 농구입니다.
답변
GIL의 목적은 무엇입니까?
CAPI 문서에는 주제에 대해 다음과 같은 내용이 있습니다.
Python 인터프리터는 스레드로부터 완전히 안전하지 않습니다. . 다중 스레드 Python 프로그램을 지원하기 위해 Python 객체에 안전하게 액세스하려면 현재 스레드가 보유해야하는 전역 인터프리터 잠금 또는 GIL이라고하는 전역 잠금이 있습니다. 잠금이 없으면 가장 간단한 작업조차도 다중 스레드 프로그램에서 문제를 일으킬 수 있습니다. 예를 들어 두 스레드가 동시에 동일한 객체의 참조 수를 증가 시키면 참조 수가 두 번이 아닌 한 번만 증가 할 수 있습니다.
즉, GIL은 상태 손상을 방지합니다. 메모리 안전 작업 만 허용되기 때문에 Python 프로그램은 분할 오류를 생성해서는 안됩니다. GIL은 이러한 보증을 다중 스레드 프로그램으로 확장합니다.
대안은 무엇입니까?
GIL의 목적이 부패로부터 상태를 보호하는 것이라면 분명한 대안 중 하나는 훨씬 더 세밀하게 고정하는 것입니다. 아마도 개체 수준에서. 문제는 다중 스레드 프로그램의 성능을 향상시키는 것으로 입증되었지만 오버 헤드가 더 많고 결과적으로 단일 스레드 프로그램이 어려움을 겪는다는 것입니다.
코멘트
- 사용자가 세분화 된 잠금을 위해 gil을 대체하는 인터프리터 옵션을 사용하여 프로그램을 실행하고 현재 프로세스가 발생했는지 여부를 읽기 전용 방식으로 알 수있게하면 좋습니다. gil.
- GIL에도 불구하고 pyodbc 모듈을 부주의하게 사용하여 다중 스레드 프로그램에서 세분화 오류를 생성했습니다. 따라서 " 분할 오류를 생성해서는 안됩니다. "는 오류입니다.