왜 파이썬이 GIL로 작성 되었습니까?


112

GIL (Global Interpreter Lock)은 파이썬에서 스레딩 (threading) 등이 터치하기 까다로운 주요 이유로 자주 인용되는 것 같습니다. "처음에 왜 그랬습니까?"라는 질문이 제기됩니다.

프로그래머가 아니기 때문에 그 이유가 무엇인지 전혀 알지 못합니다. GIL을 도입 한 논리는 무엇입니까?


10
위키 백과 문서가 있음을 주장한다 "는 GIL은 병렬-A 언어의 역 동성을 가진 지불 가격에 큰 장벽이 될 수 있습니다" 하고 말을 계속 이러한 잠금을 사용하는 이유는 포함 "단일 스레드 프로그램의 증가 속도 "모든 데이터 구조에 대한 잠금을 별도로 획득하거나 해제 할 필요가 없으며, 일반적으로 스레드 안전하지 않은 C 라이브러리를 쉽게 통합 할 수 있습니다."
Robert Harvey

3
@RobertHarvey, Dynamism는 그것과 아무 관련이 없습니다. 문제는 돌연변이입니다.
dan_waterworth


1
Java의 부호없는 숫자가 부족한 것처럼, 자신이 무엇을하고 있는지 모르는 사람들이 발로 총을 쏘는 것을 막기위한 것입니다. 불행히도, 자신이하는 일을 아는 사람 부족한 언어를 얻습니다. 파이썬은 다른 많은 방식으로 흔들 리기 때문에 부끄러운
Basic

1
@Basic은 암호화 수학을 수행하기 위해 Java에서 바이트 배열을 처리하는 표준 방법이 있어야합니다 (오랫 동안 사용하지 않았습니다). 파이썬 (예 :)에는 부호있는 숫자가 없지만 더 좋은 방법이 있기 때문에 비트 연산을 시도조차하지 않습니다.
Nick T

답변:


105

CPython, IronPython, RPython 등과 같은 몇 가지 Python 구현이 있습니다.

그들 중 일부는 GIL을 가지고 있으며 일부는 그렇지 않습니다. 예를 들어 CPython에는 GIL이 있습니다.

에서 http://en.wikipedia.org/wiki/Global_Interpreter_Lock

GIL을 사용하여 프로그래밍 언어로 작성된 응용 프로그램은 별도의 프로세스를 사용하여 완전한 병렬 처리를 달성하도록 설계 할 수 있습니다. 각 프로세스에는 고유 한 인터프리터가 있고 고유 한 GIL이 있기 때문입니다.

GIL의 장점

  • 단일 스레드 프로그램의 속도가 향상되었습니다.
  • 일반적으로 스레드로부터 안전하지 않은 C 라이브러리의 쉬운 통합

파이썬 (CPython 및 기타)이 GIL을 사용하는 이유

CPython에서 전역 인터프리터 잠금 (GIL)은 여러 원시 스레드가 한 번에 Python 바이트 코드를 실행하지 못하게하는 뮤텍스입니다. 이 잠금은 주로 CPython의 메모리 관리가 스레드로부터 안전하지 않기 때문에 필요합니다.

GIL은 특정 상황에서 멀티 스레드 CPython 프로그램이 멀티 프로세서 시스템을 최대한 활용하지 못하기 때문에 논란의 여지가 있습니다. I / O, 이미지 처리 및 NumPy 번호 크 런칭과 같은 잠재적으로 차단되거나 오래 실행되는 작업은 GIL 외부에서 발생합니다. 따라서 GIL 내부에서 많은 시간을 보내고 CPython 바이트 코드를 해석하여 GIL이 병목 현상이되는 것은 멀티 스레드 프로그램에서만 가능합니다.

파이썬에는 몇 가지 이유로 세밀한 잠금과 달리 GIL이 있습니다.

  • 단일 스레드의 경우 더 빠릅니다.

  • i / o 바운드 프로그램의 멀티 스레드 케이스에서는 더 빠릅니다.

  • C 라이브러리에서 계산 집약적 인 작업을 수행하는 CPU 바인딩 프로그램의 경우 멀티 스레드 경우가 더 빠릅니다.

  • C 확장을 더 쉽게 작성할 수 있습니다 .Py_BEGIN_ALLOW_THREADS와 Py_END_ALLOW_THREADS 매크로 사이에서 허용되는 위치를 제외하고는 파이썬 스레드 전환이 없습니다.

  • C 라이브러리를보다 쉽게 ​​래핑 할 수 있습니다. 스레드 안전성에 대해 걱정할 필요가 없습니다. 라이브러리가 스레드로부터 안전하지 않은 경우 호출하는 동안 GIL을 잠금 상태로 유지하면됩니다.

GIL은 C 확장으로 해제 할 수 있습니다. 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은 순수 파이썬에서 CPU 집약적 인 작업을 수행하는 경우에만 문제가됩니다. 여기서 프로세스 및 메시지 전달 (예 : mpi4py)을 사용하여보다 깔끔한 디자인을 얻을 수 있습니다. 파이썬 치즈 샵에는 스레드와 동일한 인터페이스를 제공하는 '프로세싱'모듈도 있습니다 (예 : threading.Thread를 processing.Process로 대체).

스레드는 GIL에 관계없이 GUI의 응답 성을 유지하는 데 사용될 수 있습니다. GIL이 성능을 손상시키는 경우 (위의 설명 참조) 스레드가 프로세스를 생성하고 완료 될 때까지 기다릴 수 있습니다.


52
신 포도처럼 들린다. 파이썬은 스레드를 제대로 수행 할 수 없으므로 스레드가 불필요하거나 나쁜 이유를 구성합니다. "부하가 적 으면 포크가 더 쉬워진다"고 진심으로? GIL은 참조 횟수 계산 GC를 사용해야하는 경우에만 모든 경우에 "빠르게"처리됩니다.
Michael Borgwardt 2013

9
s/RPython/PyPy/g. @MichaelBorgwardt 프로 GIL이 그 이유 중 하나 인 이유는 무엇입니까? 나는이 답변의 내용 중 일부 (즉, 대안에 대한 토론)가 요점에 있음에 동의하지만. 그리고 더 나은 또는 더 나쁜 것을 위해, 재계 산은 이제 거의 불가능하다. 전체 API와 코드베이스에 깊이 뿌리 내리고있다. 코드 절반을 다시 작성하지 않고 모든 외부 코드를 손상시키지 않으면 코드를 제거하는 것이 거의 불가능 합니다.

10
multiprocessing2.6 이후 표준 라이브러리를 잊지 마십시오 . 워커 풀은 단순한 병렬 처리 유형에 대한 매우 매끄러운 추상화입니다.
Sean McSomething

8
@alcalde 당신이하고있는 일을 모르거나 쓰레드가 협력 적으로 / 통신하기를 원하지 않는 경우에만. 그렇지 않으면 특히 일부 OS에서 새 프로세스를 시작하는 오버 헤드를 고려할 때 뒷면에 막대한 고통이 있습니다. 우리는 32 개의 코어를 가진 서버를 가지고 있으므로 CPython에서 완전히 활용하려면 32 개의 프로세스가 필요합니다. 그것은 "좋은 해결책"이 아닙니다. CPython의 부적합을 해결하기위한 해킹입니다.
기본

8
스레드가 Windows 이외의 플랫폼에 존재한다는 사실은 모든 상황에서 분기가 적절하지 않다는 증거가되어야합니다.
zneak

42

우선 파이썬에는 GIL이 없습니다. 파이썬은 프로그래밍 언어입니다. 프로그래밍 언어는 일련의 추상 수학 규칙 및 제한 사항입니다. Python Language Specification에는 GIL이 있어야한다고 말하는 것은 없습니다.

파이썬에는 여러 가지 구현이 있습니다. 일부는 GIL이 있고 일부는 없습니다.

GIL을 갖는 간단한 설명은 동시 코드 작성이 어렵다는 것입니다. 코드 주위에 거대한 잠금을 설정하면 코드가 항상 연속적으로 실행됩니다. 문제 해결됨!

CPython에서 특히 중요한 한 가지 목표는 C로 작성된 플러그인으로 인터프리터를 쉽게 확장하는 것입니다. 다시 한 번, 동시 코드 작성은 어렵 기 때문에 동시성이 없음을 보장하여 확장 성을보다 쉽게 ​​작성할 수 있습니다. 통역사. 또한 이러한 확장 중 다수는 동시성을 염두에두고 작성되지 않았을 수있는 기존 라이브러리 주변의 얇은 래퍼 일뿐입니다.


6
이는 자바가 부호없는 숫자 타입이 없다는 것과 같은 주장이다. 개발자들은 다른 모든 사람들이 자신보다 더 어리 석다고 생각한다.
Basic

1
@Basic-믿거 나 말거나, 심지어 멍청하지 않더라도, 가정을 단순화하는 언어를 갖는 것이 작동하기 위해 특정 것들에 대해 생각하지 않는다는 것을 의미하는 것으로 밝혀졌습니다. 의회. CPython은 간단한 멀티 스레드 응용 프로그램 (프로그램이 IO 바운드, 많은 응용 프로그램, 따라서 GIL이 중요하지 않은 곳)을 포함하여 특정 용도에 적합합니다. 특히 컬렉션에서 원자 연산을 지원한다는 사실 .
Jules

@Jules 예, 이러한 기능이 필요할 때까지 매우 편리합니다. cpython의 "선호하는"솔루션은 "그냥 c ++와 같은 다른 언어로 작성"하는 것이므로 모든 단일 파이썬 혜택을 잃게됩니다. C ++로 코드의 절반을 작성한다면 왜 파이썬에서 시작합니까? 물론 작은 API / 접착제 프로젝트의 경우 쉽고 빠르며 ETL의 경우 그 어느 때보 다 빠르지 만 무거운 물건을 들어 올리는 데 적합하지 않습니다. 하드웨어를 사용하기 위해 Java를 사용하는 것과 같습니다 ... 점프해야 할 후프는 거의 코믹합니다.
기본

16

GIL의 목적은 무엇입니까?

CAPI 문서에는 다음과 같은 주제가 있습니다.

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

즉, GIL은 상태의 손상을 방지합니다. 메모리 안전 작업 만 허용되므로 Python 프로그램은 세그먼트 오류를 ​​발생시키지 않아야합니다. GIL은 이러한 보증을 다중 스레드 프로그램으로 확장합니다.

대안은 무엇입니까?

GIL의 목적이 국가를 부패로부터 보호하는 것이라면, 한 가지 확실한 대안은 훨씬 더 미세한 곡물에 고정하는 것입니다. 아마도 객체 별 수준 일 것입니다. 이 문제는 멀티 스레드 프로그램의 성능을 향상시키는 것으로 입증되었지만 더 많은 오버 헤드가 있으며 단일 스레드 프로그램으로 인해 어려움을 겪습니다.


2
사용자가 세밀한 잠금을 위해 길을 대체하는 인터프리터 옵션으로 프로그램을 실행하고 현재 프로세스가 길의 유무에 관계없이 읽기 전용 방식으로 알 수 있다면 좋을 것입니다.
Luis Masuelli

GIL에도 불구하고 모듈 pyodbc를 부주의하게 사용했기 때문에 다중 스레드 프로그램에서 세그먼트 오류를 ​​생성했습니다. 따라서 "세그멘테이션 오류를 발생시키지 않아야합니다"는 오류입니다.
Muposat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.