자주 묻는 질문

Contents

참고: RPython에 대해 자주 묻는 질문.


PyPy란 무엇입니까?

PyPy는 RPython 변환 툴체인을 사용하여 Python으로 Python을 재구현한 것입니다.

PyPy는 언어 구현에서 생성의 용이성, 유연성, 유지 보수성, 속도 사이의 트레이드오프에 대한 새로운 해답을 찾고자 합니다. 더 자세한 내용은 목표 및 아키텍처 문서를 참조하십시오.

PyPy는 CPython을 그대로 대체할 수 있습니까?

거의 그렇습니다!

어떤 프로젝트에서든 가장 걸림돌이 되기 쉬운 부분은 확장 모듈 지원입니다. PyPy가 지원하는 확장 모듈의 수는 계속 늘어나고 있지만, 지금까지는 대부분 표준 라이브러리에 포함된 모듈에 그칩니다.

언어 기능(내장 타입과 함수 포함)은 매우 정교하고 충분히 테스트되었으므로, 프로젝트에서 확장 모듈을 많이 사용하지 않는다면 PyPy에서도 동작할 가능성이 높습니다.

알려진 차이점은 CPython과의 차이점에 정리되어 있습니다.

xyz 모듈이 PyPy에서 동작하지 않습니다: ImportError

CPython용으로 설치한 모듈을 PyPy에서 자동으로 사용할 수 있는 것은 아닙니다 — CPython 3.6과 CPython 3.7을 모두 설치한 경우, CPython 3.6용으로 설치한 모듈을 CPython 3.7에서 자동으로 사용할 수 없는 것과 마찬가지입니다. 다시 말해, xyz 모듈을 PyPy용으로 따로 설치해야 합니다.

리눅스에서 이는 apt-get이나 이와 비슷한 패키지 관리자를 사용할 수 없다는 뜻입니다. 이러한 도구는 오직 같은 패키지 관리자가 제공하는 버전의 CPython을 위한 것입니다. 그러니 지금은 이 도구들을 잊고 계속 읽어 주십시오.

요즘에는 xyz가 PyPI에 올라와 있어 <pypy> -mpip install xyz로 설치할 수 있는 경우가 매우 흔합니다. 가장 간단한 해결책은 use virtualenv (as documented here)입니다. 그런 다음 virtualenv에 진입(활성화)하고 pypy -mpip install xyz를 입력하십시오. virtualenv를 모르거나 사용하고 싶지 않다면 pypy -m ensurepip을 실행한 뒤 로컬에서 pip을 사용할 수도 있습니다. ensurepip module은 저희가 제공하는 PyPy 다운로드에 내장되어 있습니다. pip을 사용할 때의 모범 사례는 항상 <python> -mpip ... 형태로 호출하는 것이지만, 명령줄에서 pip을 직접 호출하고 싶다면 pypy -mensurepip --default-pip을 호출해야 합니다.

C 컴파일러에서 오류가 발생한다면 해당 모듈은 지원되지 않는 기능을 사용하는 CPython C 확장 모듈입니다. See below.

또는 xyz 모듈을 PyPI에서 구할 수 없거나 virtualenv를 사용하고 싶지 않다면, xyz의 소스 코드를 내려받아 zip/tarball의 압축을 풀고 소스 디렉터리 안에서 표준 명령인 pypy -mpip install .을 실행하십시오. (참고: 여기서는 python 대신 pypy를 사용합니다.) 평소와 마찬가지로 전역 설치를 하려면 sudo로 명령을 실행해야 할 수도 있습니다.

샌드박스화된 PyPy에서 xyz 모듈이 작동하지 않습니까?

죄송하지만 sandboxed PyPy에서는 확장 모듈을 하나도 임포트할 수 없습니다. 사용 가능한 내장 모듈조차도 매우 제한적입니다. PyPy의 샌드박싱은 훌륭한 개념 증명이며 제 생각에는 의심할 여지 없이 안전하지만, 어디까지나 개념 증명일 뿐입니다. 현재로서는 의욕 있는 개발자의 작업이 어느 정도 필요합니다. 하지만 그때까지는 “순수 Python” 예제, 즉 거의 아무것도 임포트하지 않는(또는 재귀적으로 순수 Python 모듈만 임포트하는) 프로그램에만 사용할 수 있습니다.

C 확장 모듈은 PyPy에서 동작합니까?

먼저 일부 Linux 배포판(예: Ubuntu, Debian)은 PyPy를 여러 패키지로 나누어 제공한다는 점에 유의하십시오. “pypy”라는 패키지를 설치했다면, 아래 내용이 동작하려면 “pypy-dev”도 설치해야 할 수 있습니다.

C 확장 모듈(C-API를 사용해 작성한 모듈)을 지원하므로, 이러한 모듈은 수정 없이 그대로 실행됩니다. 이 기능은 1.4 릴리스부터 PyPy에 포함되어 있으며, 지원이 거의 완성되었습니다. PyPy에서 CPython 확장 모듈은 참조 카운팅을 에뮬레이트해야 하므로 CPython에서보다 훨씬 느린 경우가 많습니다. JIT가 최적화할 수 있는 순수 Python이나 CFFI 버전으로 C 확장을 대체하면 더 빠른 경우가 많습니다. xyz 모듈을 설치하려는데 이 모듈에 같은 코드의 C 버전과 Python 버전이 모두 있다면, 먼저 C 버전을 비활성화해 보십시오. 보통 setup.py의 몇 줄만 바꾸면 쉽게 비활성화할 수 있습니다.

ctypes 기반 확장을 완전히 지원합니다. 하지만 최상의 성능을 위해서는 C 코드와의 인터페이스에 cffi 모듈을 사용하실 것을 권장합니다.

참조 카운팅 의미론을 어떻게 관리하는지에 대한 자세한 내용은 rawrefcount를 참조하십시오.

PyPy는 어떤 플랫폼에서 실행됩니까?

PyPy는 현재 다음을 지원합니다.

  • 널리 쓰이는 대부분의 운영 체제(Linux 32/64비트, Mac OS X 64비트, Windows 32/64비트, OpenBSD, FreeBSD)에서 동작하는 x86 머신,
  • ARM64라고도 알려진 64비트 AArch,
  • Linux를 실행하는 ARM 하드웨어(VFPv3를 지원하는 ARMv6 또는 ARMv7) (이 하드웨어용 사전 빌드 바이너리는 더 이상 제공하지 않습니다),
  • Linux를 실행하는 PPC64의 빅 엔디언 및 리틀 엔디언 변형,
  • Linux를 실행하는 s390x

PyPy는 Linux 머신에서 정기적이고 광범위하게 테스트됩니다. Mac과 Windows에서도 동작하며 해당 플랫폼에서도 테스트되지만, 저희 대부분은 Linux를 사용하므로 수정 사항은 외부 기여에 의존할 수 있습니다.

소스에서 부트스트랩하려면 PyPy는 CPython 2.7과 PyPy 2.7 중 하나를 사용할 수 있습니다. 교차 변환은 사실상 지원되지 않습니다. 예를 들어 32비트 PyPy를 빌드하려면 32비트 환경이 필요합니다.

PyPy는 어떤 Python 버전을 구현합니까?

RPython이 2.7용으로 작성되었기 때문에 PyPy는 앞으로도 항상 2.7을 지원합니다. 또한 PyPy는 여러 Python3 버전을 지원합니다. 최신 릴리스에 대해서는 release notes를 참고하십시오. 보통은 Python3 버전을 한두 개 지원합니다.

PyPy에는 GIL이 있습니까? 그 이유는 무엇입니까?

네, PyPy에는 GIL이 있습니다. GIL을 제거하는 것은 매우 어렵습니다. CPython에서는 두 가지 문제가 있습니다. (1) GC, 이 경우에는 참조 카운팅이고, (2) Python 언어 전체입니다.

PyPy에서 어려운 문제는 (2)번입니다. 이는 가변 객체를 한 스레드에서 변경하는 동안 다른 스레드에서 동시에 읽으면 어떤 일이 일어나는지와 같은 문제를 말합니다. 이는 모든 가변 타입에 해당하는 문제입니다. Python 인터프리터 전체에 걸쳐 신중한 검토와 수정(주로 세분화된 락)이 필요합니다. Jython/IronPython이 보여 주었듯이 완전히 불가능하지는 않지만, 상당히 큰 작업입니다. 여기에는 어떤 효과가 사용자(즉, Python 프로그래머)에게 괜찮은지 아닌지에 대한 미묘한 결정도 포함됩니다.

CPython에는 참조 카운팅이라는 문제 (1)이 추가로 있습니다. PyPy에서는 이 하위 문제가 더 간단합니다. GC가 멀티스레드를 인식하도록 만들기만 하면 됩니다. 이는 CPython보다 PyPy에서 효율적으로 구현하기가 더 쉽습니다. 하지만 이것으로 문제 (2)가 해결되지는 않습니다.

PyPy의 Software Transactional Memory (STM) 버전을 지원하기 위한 작업이 있었다는 점에 유의하십시오. 이 버전은 GIL 없이 동작하면서도 Python 프로그래머에게는 GIL이 있는 것 같은 완벽한 착각을 계속 제공하는 대안 PyPy가 될 것입니다. 이 작업은 자체적인 기술적 어려움 때문에 현재 다소 정체되어 있습니다.

numpy, numpypy, micronumpy는 어떻습니까?

일찍이 2011년에 PyPy 팀은 PyPy에서 numpy를 다시 구현하기 시작했습니다. 이는 두 부분으로 이루어져 있습니다:

  • 내장 모듈 pypy/module/micronumpy: 이 모듈은 RPython으로 작성되었으며 numpy.core.multiarray 모듈의 내용을 대략적으로 포함합니다. 혼란스럽게도 이 모듈은 PyPy에서 _numpypy라는 이름으로 제공됩니다. 이 모듈은 PyPy의 모든 공식 릴리스에 기본으로 포함되어 있습니다(다만 향후 제외될 수도 있습니다).
  • 저희가 관리하며 비공식적으로 numpypy라고 부르는 공식 numpy 저장소의 fork: 업스트림 numpy와의 주요 차이점은 C로 작성된 numpy.core.multiarray 대신 RPython으로 작성된 micronumpy 모듈을 기반으로 한다는 점입니다.

numpy와 numpypy 중 어느 것을 설치해야 합니까?

요약: numpy를 사용하십시오. pypy -m pip install numpy를 실행하여 설치할 수 있습니다.

업스트림 numpy는 C로 작성되어 있으며 cpyext 호환성 계층 위에서 실행됩니다. 오늘날 cpyext는 충분히 성숙하여 업스트림 numpy가 테스트 스위트를 통과하므로, 업스트림 numpy를 그대로 사용해도 됩니다. numpy의 주요 단점은 cpyext가 느리기로 악명이 높다는 점이며, 그 때문에 numpypy에 비해 성능이 떨어집니다. 그러나 HPy를 사용할 수 있게 되면 같은 속도에 도달할 것으로 예상하므로, 저희는 이를 개선하기 위해 적극적으로 작업하고 있습니다.

반면 numpypy는 RPython으로 작성되었기 때문에 JIT에 더 친화적이고 호출 속도도 매우 빠릅니다. 하지만 재구현이기 때문에 완전한 호환성을 갖추기는 어렵습니다. 이 프로젝트는 수년에 걸쳐 서서히 성숙했고, 마침내 행렬 계산 속도를 높이기 위해 LAPACK과 BLAS 라이브러리를 호출할 수 있게 되었으며, 업스트림 numpy와 약 80% 수준의 동등성에 도달했습니다. 그러나 80%는 100%와는 거리가 멉니다. cpyext/numpy 호환성이 완성되었으므로 numpypy에 대한 지원을 중단했습니다.

PyPy는 꼬리 호출(Tail Call)을 CPython보다 더 영리하게 처리합니까?

아니요. PyPy는 내장 디버거 기능을 포함하여 Python 언어 설계를 따릅니다. 이 때문에 꼬리 호출을 할 수 없으며, 이는 Guido van Rossum이 두 블로그 게시물에서 정리한 바와 같습니다. 게다가 JIT도 Stackless도 이 점을 전혀 바꾸지 않습니다.

PyPy는 얼마나 빠릅니까?

이는 실제로 코드에 따라 크게 달라집니다. 순수 Python 알고리즘 코드에서는 매우 빠릅니다. 보다 일반적인 Python 프로그램에서는 대체로 CPython 2.7보다 3배 빠릅니다. 저희 benchmarking site와 jit documentation도 관심 있게 살펴보실 만합니다.

Your tests are not a benchmark: 테스트는 정확히 한 번만 실행되기 때문에 PyPy에서 느린 경향이 있습니다. 좋은 테스트라면 코드의 다양한 코너 케이스를 실행합니다. 이는 JIT 컴파일러에 불리한 경우입니다. 또한 저희 JIT는 워밍업 비용이 매우 높다는 점에 유의하십시오. 즉, 어떤 프로그램이든 처음에는 느립니다. CPython과 실행 시간을 비교하려면 비교적 단순한 프로그램이라도 최소한 1초는 실행해야 하며, 가급적 몇 초 이상 실행하는 것이 좋습니다. 크고 복잡한 프로그램은 JIT를 워밍업하는 데 훨씬 더 많은 시간이 필요합니다.

3줄짜리 벤치마크를 작성했는데 CPython보다 빠르지 않습니다. 왜 그렇습니까?

세 줄짜리 벤치마크는 정말로 아무것도 하지 않는 벤치마크이거나(이 경우 PyPy가 CPython보다 훨씬 빠를 가능성이 높습니다), 그보다 흔하게는 대부분의 시간을 C 코드에서 작업을 수행하는 데 쓰는 벤치마크입니다.

예를 들어, 복잡한 SQL 연산 하나를 반복해서 실행하는 루프는 SQL 데이터베이스의 성능만 측정하게 됩니다. 마찬가지로, 피보나치 수열의 원소를 많이 계산하면 매우 큰 정수를 빌드하게 되므로, 이는 긴 정수 라이브러리의 성능만을 측정하게 됩니다. 이 라이브러리는 CPython에서는 C로, PyPy에서는 RPython으로 작성되어 있지만, 결국은 같은 것을 측정하는 셈입니다.

PyPy는 Python으로 작성된 코드의 실행 속도를 높입니다.

JIT가 이미 컴파일된 기계어 코드를 덤프해 두었다가 다시 불러올 수는 없습니까?

아니요, 그렇게 할 방법은 찾지 못했습니다. JIT는 수많은 상수 주소를 포함하는 기계어 코드를 생성합니다 — 여기서 상수란 기계어 코드가 생성되는 시점에 상수라는 뜻입니다. 그 대다수는 아마도 실행 파일 안에서 알기 쉬운 링크 이름과 함께 찾을 수 있는 상수가 전혀 아닐 것입니다. 예를 들어 Python 클래스의 주소는 항상 사용되지만, Python 클래스는 실행 파일에서 정적으로 오는 것이 아닙니다. 프로그램을 다시 시작할 때마다 새로 생성됩니다. 따라서 이전(이제는 종료된) 프로세스의 주소를 새 프로세스의 주소로 대응시키는 매우 고도화된 방법 없이는 기계어 코드를 저장했다가 다시 불러오는 것이 완전히 불가능합니다. 이 방법에는 (이제는 종료된) 객체에 대해 세웠던 이전의 모든 가정이 새 객체에 대해서도 여전히 참인지 확인하는 일까지 포함됩니다.

타입 어노테이션이 PyPy의 성능에 도움이 됩니까?

성능 향상을 위해 제안되고 있는 타입 어노테이션의 두 가지 예로는 Cython 타입과 PEP 484 - Type Hints가 있습니다.

Cython 타입은 그 구조상 C 선언과 유사합니다. 예를 들어, 지역 변수나 인스턴스 속성을 "cdef int"로 선언하여 머신 워드를 강제로 사용하게 할 수 있습니다. 이는 일반적인 Python 의미론을 바꿉니다(예: 오버플로 검사가 없어지고, 그곳에 다른 타입의 객체를 쓰려고 하면 오류가 발생합니다). 이를 통해 약간의 추가 성능을 얻을 수 있지만 정확한 이점은 불분명합니다. 예를 들어 현재(2015년 1월) 저희는 머신 워드 정수를 인스턴스에 직접 저장하는 기법을 연구하고 있으며, 이 기법은 사용자가 "cdef int"를 지정하지 않아도 그 이점의 일부를 제공할 것입니다.

반면 PEP 484 - Type Hints는 성능을 고려한다면 거의 완전히 쓸모가 없습니다. 첫째, 이름에서 알 수 있듯이 타입 힌트는 힌트일 뿐입니다. PEP 484에 명시된 대로 여전히 런타임에 검사해야 합니다. 아니면 타입 애너테이션이 잘못되었을 때 매우 알아보기 힘든 크래시가 발생하는 모드라도 괜찮다고 생각하실 수도 있습니다. 하지만 그런 경우라도 속도상의 이점은 극히 미미할 것입니다.

여기에는 몇 가지 이유가 있습니다. 그중 하나는 애너테이션이 잘못된 수준에 있다는 점입니다(예를 들어 PEP 484의 “int”는 Python 3의 int 타입에 대응하는데, 이 타입은 반드시 머신 워드 하나에 들어가는 것은 아닙니다. 게다가 더 나쁘게도 “int” 애너테이션은 임의의 int 서브클래스까지 허용합니다). 또 다른 이유는 좋은 코드를 생성하려면 훨씬 더 많은 정보가 필요하다는 점입니다(예를 들어 “여기서 호출되는 이 f()는 실제로 저기에 있는 바로 그 함수를 의미하며, 절대 몽키 패치되지 않음”과 같은 정보입니다. 참고로 len()이나 list()도 마찬가지입니다). 세 번째 이유는 PyPy의 JIT 트레이스에 있는 일부 “가드(guard)”에는 명확하게 대응하는 타입이 사실상 없다는 점입니다(예를 들어 “이 dict는 지금까지 __hash__를 오버라이드하지 않는 키만 사용하고 있으므로 더 효율적인 구현을 사용했음”과 같은 가드입니다). 많은 가드(guard)는 타입과 아예 아무런 대응 관계도 없습니다(“이 클래스 속성은 수정되지 않았음”, “루프 카운터가 0에 도달하지 않았으므로 GIL을 해제할 필요가 없음” 등).

현재 PyPy가 작동하는 방식만으로도 PyPy는 PEP 484가 제공할 수 있는 것보다 훨씬 더 유용한 정보를 도출할 수 있으며, 이는 자동으로 이루어집니다. 저희가 아는 한, 빠른 1차 패스(first-pass) JIT 같은 다른 기법을 PyPy에 추가하더라도 이는 마찬가지입니다.

PyPy의 변환 툴체인을 Python 외의 다른 언어에도 사용할 수 있습니까?

예. PyPy 인터프리터를 변환하는 도구 모음은 상당히 범용적이어서, Python뿐만 아니라 어떤 언어의 인터프리터든 최적화된 버전을 만드는 데 사용할 수 있습니다. 물론 이러한 인터프리터들도 PyPy가 Python에 제공하는 것과 같은 기능을 활용할 수 있습니다. 바로 다양한 언어로의 변환, 스택리스(stackless) 기능, 가비지 컬렉션, 임의 길이 정수 같은 여러 가지 기능의 구현 등입니다.

현재 Ruby 인터프리터인 Topaz, PHP 인터프리터인 Hippy, JavaScript interpreter의 초기 버전 (Leonardo Santagada가 Summer of PyPy 프로젝트로 작업), Prolog interpreter (Carl Friedrich Bolz가 학사 학위 논문으로 작업), 그리고 SmallTalk interpreter (스프린트 중에 제작)가 있습니다. 또한 미완성 Scheme 구현도 있습니다.

PyPy 개발에는 어떻게 참여할 수 있습니까? 스프린트에 참가할 수 있습니까?

물론 스프린트에 참여하실 수 있습니다! 저희는 언제나 새로 오시는 분들을 환영하며, 이분들이 프로젝트를 시작할 수 있도록 최대한 도와 드리려고 노력합니다. 저희는 튜토리얼을 제공하고, 새로 오신 분들을 경험 많은 PyPy 개발자와 짝을 지어 드립니다. 새로 오시는 분들은 스프린트에 오시기 전에 Python 경험을 어느 정도 갖추고 PyPy 문서도 일부 읽어 두셔야 합니다.

스프린트에 참가하는 것이 보통 PyPy 개발에 입문하는 가장 좋은 방법입니다. 막히거나 조언이 필요하면 저희에게 문의하십시오. IRC는 피드백을 가장 빠르게 받을 수 있는 방법이며(적어도 하루 중 일부 시간대에는 그렇습니다. PyPy 개발자 대부분이 유럽에 있기 때문입니다), 긴 논의에는 mailing list가 더 적합합니다.

또한 https://github.com/pypy/pypy 에 있는 GitHub 저장소를 통한 참여도 권장합니다. issue tracker에서 이슈를 등록하고 논의할 수 있으며, pull requests도 환영합니다.

OSError: … cannot restore segment prot after reloc… 도와주시겠습니까?

Linux에서 SELinux가 활성화되어 있으면 “OSError: externmod.so: cannot restore segment prot after reloc: Permission denied.”와 비슷한 오류가 발생할 수 있습니다. 이 오류는 구성 과정에서 C 컴파일러를 약간 변칙적으로 사용하기 때문에 발생하며, root 권한으로 다음 명령을 실행하여 비활성화할 수 있습니다:

# setenforce 0

이렇게 하면 SELinux의 보호 기능이 비활성화되어 PyPy가 올바르게 구성될 수 있습니다. SELinux가 필요하다면 반드시 다시 활성화하십시오!

버그는 어떻게 보고해야 합니까?

저희 버그 트래커는 여기에 있습니다: https://github.com/pypy/pypy/issues/

누락된 기능이나 CPython과의 비호환성은 버그로 간주하며, 이에 대한 제보를 언제나 환영합니다. (알려진 비호환성 목록도 참고하십시오.)

“PyPy가 크래시하거나 이상한 예외가 발생합니다” 같은 종류의 버그에 대해서는 다음 사항에 유의하십시오. 저희가 직접 버그를 재현하지 못하면 아무것도 할 수 없습니다. gdb에서 얻은 트레이스백이나 코어 덤프로는 아무것도 할 수 없습니다. 이는 표준 PyPy가 디버그 심볼 없이 컴파일되기 때문만은 아닙니다. 진짜 이유는 PyPy에서는 C 수준의 트레이스백이 대개 전혀 도움이 되지 않기 때문입니다. PyPy를 디버깅하는 일은 번거로울 수 있습니다.

명확하고 유용한 버그 보고서의 예시입니다. (물론 문제를 재현하기가 정말 어려울 때도 있지만, 그래도 재현해 보시기 바랍니다.)

좀 더 자세히 설명하면 다음과 같습니다.

  • 먼저 정확한 PyPy 버전과 OS를 알려 주십시오.
  • 버그가 “pypy --jit off”에서 재현되는지 여부를 알면 조사 범위를 좁히는 데 도움이 될 수 있습니다. “pypy --jit off”가 항상 제대로 동작한다면 문제는 JIT에 있을 수 있습니다. 그렇지 않다면 그 부분은 무시해도 된다는 것을 알 수 있습니다.
  • 오픈 소스 구성 요소만 사용하다가 버그를 겪으셨다면, 저희가 직접 문제를 재현할 수 있도록 단계별 안내를 제공해 주십시오. 저희가 PyPy 외의 다른 프로그램에 대해 무언가 알고 있으리라고 가정하지 마십시오. 저희는 귀하의 것과 비슷한 머신에서 아무것도 추가되지 않은 PyPy부터 시작하여 같은 문제가 나타날 때까지 (추측하거나 스스로 알아낼 필요 없이) 한 단계씩 그대로 따라 할 수 있는 안내를 원합니다. (가능하다면 단계 수와 실행에 걸리는 시간을 줄여 보셔도 좋지만, 필수는 아닙니다.)
  • 버그가 비공개 소스(Closed Source) 구성 요소와 관련되어 있거나, 저희가 직접 모두 설치하기에는 오픈 소스 구성 요소가 너무 많은 경우에는 버그를 재현할 수 있는 머신에 대한 임시 ssh 접근 권한을 저희에게 제공해 주실 수도 있을 것입니다. 또는 문제가 발생하는 VirtualBox나 VMWare 가상 머신을 저희가 내려받을 수도 있을 것입니다.
  • 저희에게 접근 권한을 주려면 저희가 ssh 이외의 도구를 사용하거나, 일정을 미리 잡거나, NDA에 서명해야 하는 경우, 소액의 비용을 받는 상업 지원 계약을 고려할 수 있습니다.
  • 그마저도 불가능하시다면, 죄송하지만 저희가 도와드릴 수 없습니다.

물론 문제를 직접 디버깅해 볼 수도 있으며, #pypy IRC 채널에서 문의하시면 시작하는 데 도움을 드릴 수 있습니다. 하지만 각오하십시오. 골치 아픈 PyPy 문제를 디버깅하려면 보통 자동 생성된 C 코드에서 gdb를 상당히 많이 사용해야 하고, PyPy 자체의 RPython 소스 코드부터 GC, 경우에 따라서는 JIT에 이르기까지 관련된 여러 구성 요소를 적어도 어느 정도는 알고 있어야 합니다.

PyPy는 왜 Git으로 전환하고 GitHub로 옮겼습니까?

PyPy는 2010년에 SVN에서 Mercurial and bitbucket으로 이전했습니다. 2020년에 bitbucket이 예고 없이 Mercurial 지원을 중단했을 때, 우리는 Git/GitHub로 이전할지를 두고 논의했습니다. 당시 우리는 (1) Git 워크플로가 우리 방식에는 Mercurial 워크플로만큼 잘 맞지 않으며, (2) “다른 모두가 그렇게 하니까”라는 이유로 GitHub로 옮기자는 것은 근거가 빈약한 인자라고 결론 내렸습니다.

(1)의 경우 몇 가지 문제가 있지만, 아마 가장 중요한 것은 PyPy 저장소에 이름 있는(named) 브랜치가 수천 개나 있다는 점입니다. Git에는 이에 해당하는 개념이 없습니다. 물론 Git에도 브랜치가 있지만, 이는 Mercurial에서 북마크라고 부르는 것입니다. 여기서 말하는 것은 북마크가 아닙니다.

브랜치가 10개뿐인 저장소에서는 (저장소가 아무리 크더라도) git 브랜치와 이름 있는 브랜치(named branch)의 차이가 그리 중요하지 않습니다. 하지만 PyPy의 경우 당시 브랜치가 1840개나 있었습니다. 물론 지금은 대부분 닫혀 있습니다. 하지만 저희는 과거의 커밋을 보고 그 커밋이 어느 브랜치에서 만들어졌는지 알 수 있는 능력을 (지금도, 앞으로도) 꼭 유지하고 싶습니다. Git 브랜치와 Mercurial 브랜치 사이에는 차이가 있으며, Git에서는 이것이 항상 가능하지는 않습니다— 저희는 열심히 찾아보았지만, 이러한 워크플로를 구현할 내장 방법은 없습니다.

아직도 납득이 되지 않으십니까? 커밋이 세 개 있는 다음 git 저장소를 생각해 보십시오. 커밋 #2는 부모가 #1이며 git 브랜치 “A”의 헤드이고, 커밋 #3도 부모가 #1이지만 git 브랜치 “B”의 헤드입니다. 커밋 #1이 만들어졌을 때, 그 커밋은 브랜치 “A”에 있었습니까, 아니면 “B”에 있었습니까? (헤드가 마찬가지로 앞으로 이동했거나 아예 완전히 삭제된 또 다른 브랜치였을 수도 있습니다.)

이 논의 직후 우리는 git notes를 발견했습니다. 이 기능을 사용하면 각 git 커밋에 원래 브랜치를 나타내는 노트를 달 수 있습니다. 완벽한 해결책은 아니지만, 타격을 어느 정도 줄여 줍니다.

저희의 개발 방향은 PyPy를 오픈 소스 프로젝트 생태계에 통합하는 쪽으로 바뀌었습니다. 그에 따라 PyPy는 여러 인기 Python 프로젝트에서 테스트되기 시작했으며, conda-forge에서도 사용할 수 있게 되었습니다. 이에 따라 다른 개발 그룹과 상호작용할 때 생기는 마찰을 줄이는 일이 중요해졌습니다. 알고 보니 그들 대부분은 Git만 지원하는 GitHub를 사용하고 있었습니다. 그래서 2023년 말에 저희는 주요 개발 환경을 Git/GitHub로 옮겼습니다. 공개적인 상호작용이 그다지 많지 않은 저장소는 여전히 https://foss.heptapod.net/pypy/ 에 남아 있습니다.

PyPy의 Windows 64 지원을 개선하려면 무엇이 필요합니까?

PyPy 7.3.5부터 PyPy는 Windows 64비트를 지원합니다. sizeof(long) != sizeof(void *)인 플랫폼은 Windows뿐인데 RPython의 기반 데이터 타입은 long이어서, 이를 지원하는 일은 쉽지 않았습니다. 이제 그 고비는 넘긴 것으로 보이며, Windows 버전을 CPython과 같은 수준으로 끌어올리는 데 도움을 주신다면 환영합니다. 특히 winconsoleio, Windows 감사 이벤트, Windows faulthandler 같은 Windows 전용 기능은 아직 지원하지 않습니다. 성능은 Linux64보다 뒤처질 수 있으며, wininstaller 브랜치는 아직 완성되지 않았습니다.

도움은 언제든 환영합니다!

PyPy는 Python2를 언제까지 지원합니까?

RPython은 Python2를 기반으로 만들어졌고 이 점이 바뀔 가능성은 극히 낮으므로, PyPy의 Python2 버전은 “영원히”, 즉 PyPy 자체가 존재하는 한 계속 유지될 것입니다.