Python GIL을 조기에 제거하려고하면 성능이 저하되었습니다. 왜 그렇습니까?


13

Python 제작자 인 Guido Van Rossum 의이 게시물 은 Python에서 GIL을 제거하려는 초기 시도를 언급합니다.

이것은 실망스런 결과와 함께 이전에 시도되었으므로 직접 노력하기를 꺼려합니다. 1999 년 그레그 스타 인 (Mark Hammond?)은 GIL을 제거하는 파이썬 포크 (1.5)를 만들어 모든 가변 데이터 구조에 대한 세밀한 잠금으로 대체했습니다. 또한 글로벌 가변 데이터 구조에 대한 많은 의존성을 제거하는 패치를 제출했습니다. 그러나 벤치마킹 후 가장 빠른 잠금 기본 요소 (당시 Windows)가있는 플랫폼에서도 단일 스레드 실행 속도가 거의 두 배로 느려짐을 알 수있었습니다. 이는 두 CPU에서 약간 더 많은 작업을 수행 할 수 있음을 의미합니다. GIL이있는 단일 CPU보다 GIL없이 수행됩니다. 이것으로 충분하지 않았으며 Greg의 패치는 망각으로 사라졌습니다. (성에 대한 Greg의 저술을 참조하십시오.)

실제 결과에 대해서는 거의 논쟁 할 수 없지만 왜 이런 일이 일어 났는지 궁금합니다. CPython에서 GIL을 제거하는 것이 어려운 이유는 레퍼런스 카운팅 메모리 관리 시스템 때문일 것입니다. 일반적인 파이썬 프로그램을 호출 Py_INCREF하고 Py_DECREF우리가 주위에 잠금 장치를 포장한다면 그에게 중요한 경쟁 포인트를 만들고, 수천 또는 수백만 번.

그러나 원자 기본 요소를 추가하면 단일 스레드 프로그램 이 느려지는 이유를 이해할 수 없습니다 . 각 Python 객체의 refcount 변수가 원자 기본 요소가되도록 CPython을 수정했다고 가정하십시오. 그리고 참조 카운트를 증가시킬 필요가있을 때 원자 단위 증가 (fetch-and-add 명령어)를 수행합니다. 이것은 파이썬 참조 계산을 스레드로부터 안전하게 만들고 잠금 경합이 없기 때문에 단일 스레드 응용 프로그램에서 성능 저하가 없어야합니다.

그러나 아아, 나보다 똑똑한 많은 사람들이 시도하고 실패했기 때문에 분명히 여기에 뭔가 빠져 있습니다. 이 문제를보고있는 방식에 어떤 문제가 있습니까?


1
참조 카운트 작업 만이 동기화가 필요한 유일한 장소는 아닙니다. 이 인용문에는 "모든 변경 가능한 데이터 구조에 대한 세분화 된 잠금"이 언급되어 있는데, 여기에는 모든 목록과 사전 객체에 대해 최소한 뮤텍스가 포함되어 있다고 가정합니다. 또한 원자 정수 연산이 경합에 관계없이 비원 자적 연산만큼 효율적이라고 생각하지 않습니다. 소스가 있습니까?

원자 작업이 비 원자에 해당하는 것보다 느리기 때문입니다. 그것이 단지 하나의 명령이기 때문에 그것이 후드 아래 사소한 것을 의미하지는 않습니다. 토론을 위해 이것을보십시오
Móż

답변:


9

나는 Greg Stein Python 포크에 익숙하지 않으므로이 비교를 추론 적 역사적 비유로 할인하십시오. 그러나 이것은 단일 인프라에서 다중 스레드 구현으로 이동 하는 많은 인프라 코드베이스 의 역사적 경험이었습니다 .

기본적으로 1990 년대에 연구 한 모든 Unix 구현 (AIX, DEC OSF / 1, DG / UX, DYNIX, HP-UX, IRIX, Solaris, SVR4 및 SVR4 MP)은 모두 " 세밀한 잠금-이제 더 느립니다 !! " 문제. 내가 따르는 DBMS (DB2, Ingres, Informix, Oracle 및 Sybase)도 모두 통과했습니다.

"단일 스레드를 실행할 때 이러한 변경 사항으로 인해 속도가 느려지지 않는다"고 들었습니다. 그런 식으로 작동하지 않습니다. 조건부 검사의 간단한 동작은 "멀티 스레드를 실행하고 있습니까?" 파이프 라인이 많은 CPU에서 실제 오버 헤드를 추가합니다. 공유 데이터 구조의 무결성을 매우 자주 호출해야하기 때문에 원자 작업과 가끔씩 스핀 스핀이 추가되어 매우 느립니다. 1 세대 잠금 / 동기화 프리미티브도 느 렸습니다. 대부분의 구현 팀은 다양한 장소에서 얼마나 많은 인터록 보호가 필요한지에 따라 다양한 "강도"로 여러 종류의 프리미티브를 추가합니다. 그런 다음 초기에 잠금 기본 요소를 제압 한 위치가 실제로 올바른 위치가 아니므로 발견 된 병목 현상을 중심으로 프로파일 링하고 설계해야했습니다. 그리고 체계적으로 로토 틸. 이러한 문제 중 일부는 결국 OS 또는 하드웨어 가속을 얻었지만 전체 진화에는 최소 3-5 년이 걸렸습니다. 한편, MP 또는 MT 버전은 성능 측면에서 절뚝 거리고있었습니다.

그렇지 않으면 정교한 개발 팀은 이러한 속도 저하가 기본적으로 지속적이고 다루기 힘든 삶의 사실이라고 주장했습니다. 예를 들어, IBM은 경쟁 후 최소 5 년 동안 AIX를 SMP 지원으로 거부했습니다. 단 일 스레드만으로도 순전히 더 나았습니다. Sybase는 동일한 인수 중 일부를 사용했습니다. 일부 팀이 결국 등장한 유일한 이유는 단일 스레드 성능을 더 이상 CPU 수준에서 합리적으로 향상시킬 수 없기 때문입니다. 그들은 MP / MT로 이동하거나 점점 경쟁이 치열한 제품을 수용해야했습니다.

활성 동시성이 어렵습니다. 그리고 기만적입니다. 모두들 "이것은 나쁘지 않을 것"이라고 생각하며 서두르고 있습니다. 그런 다음 그들은 급경사를 치고 뚫고 지나갔습니다. 나는 12 개 이상의 유명 브랜드, 잘 자금을 지원하는 똑똑한 팀에서 이런 일이 발생하는 것을 보았습니다. 일반적으로 MP / MT 제품의 경우 멀티 스레드를 선택하여 "성능면에서 원래 위치로 돌아가려면"최소 5 년이 소요 된 것 같습니다. 대부분은 여전히 ​​10 년 후에도 MP / MT 효율성 / 확장 성을 의미있게 개선하고있었습니다.

따라서 GvR의 승인과 지원이 없다면 아무도 파이썬과 GIL에 대한 긴 여정을 밟지 않았습니다. 그들이 오늘 그렇게하더라도, "와우! 우리는 정말 MT 혹을 넘겼습니다!"라고 말하기 전에 그것은 파이썬 4.x 기간이었습니다.

아마도 파이썬과 런타임을 다른 모든 상태 저장 인프라 소프트웨어 (모든 언어 런타임, 운영 체제, 트랜잭션 모니터 및 이전의 데이터베이스 관리자)와 분리하는 마법이있을 수 있습니다. 그러나 그렇다면 독특하거나 거의 동일합니다. GIL 동등 물을 제거하는 다른 모든 사람들은 MT-not에서 MT-hot에 이르기까지 5 년 이상 열심히 노력하고 투자했습니다.


2
+1 상당히 작은 개발자 팀과 함께 멀티 스레드 Tcl에 많은 시간이 걸렸습니다. 코드는 그 전에 MT 안전했지만 대부분 메모리 관리에서 동적 성능이 매우 열악하다고 생각되는 성능 문제가있었습니다. 이 경험은 실제로 가장 일반적인 용어 이외의 다른 것으로 파이썬으로 이어지지는 않습니다. 두 언어는 완전히 다른 스레딩 모델을 가지고 있습니다. 그냥… slog를 기대하고 이상한 버그를 기대하십시오…
Donal Fellows

-1

또 다른 야생의 가설 : 1999 년 리눅스와 다른 Unices는 futex(2)( http://en.wikipedia.org/wiki/Futex ) 와 같은 성능 동기화를하지 않았습니다 . 그것들은 2002 년경에 왔으며 2004 년경 2.6으로 합병되었습니다.

모든 내장 데이터 구조는 동기화 잠금 비용이 많이 들기 때문에 많은 비용이 듭니다. operationsσᶎ는 이미 원자 작업이 저렴하지 않다고 지적했다.


1
이것을 백업 할 것이 있습니까? 아니면 이것은 거의 추측입니까?

1
GvR 인용문은 "가장 빠른 잠금 기본 요소 (현재는 Windows)가있는 플랫폼에서의 성능"을 설명하므로 Linux의 느린 잠금은 관련이 없습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.