자주 묻는 질문¶
Contents
- 자주 묻는 질문
- RPython이란 무엇입니까?
- RPython으로 일반 Python 프로그램을 C로 컴파일할 수 있습니까?
- 이 RPython 언어는 무엇입니까?
- RPython은 Zope의 Restricted Python과 관련이 있습니까?
- 일부 독스트링에 보이는
"NOT_RPYTHON"은 무엇입니까? - 그냥 Python 구문 트리를 가져다가 Lisp로 바꾸면 되지 않겠습니까?
- 제 프로그램을 RPython으로 다시 작성해야 합니까?
- RPython 툴체인에는 어떤 백엔드가 있습니까?
- LLVM을 사용할 수 있습니까?
- PyPy 컴파일 시 스왑이 발생하거나 메모리가 부족해지는 경우
- 직접 만든 인터프리터는 어떻게 컴파일합니까?
- PyPy용 RPython 모듈을 독립적으로 변환할 수 있습니까?
- 변환기는 왜 변환 도중에 만델브로 프랙털을 그립니까?
RPython이란 무엇입니까?¶
RPython은 프로그래밍 언어, 특히 동적 언어의 인터프리터와 가상 머신을 구현하기 위한 프레임워크입니다.
RPython으로 일반 Python 프로그램을 C로 컴파일할 수 있습니까?¶
아닙니다. RPython은 Python 컴파일러가 아닙니다.
Python에서는 정적 분석으로 프로그램이 다루게 될 타입에 대해 무언가를 증명하는 것이 대체로 불가능합니다. Python에 익숙하다면 이는 분명할 것이지만, 확신이 서지 않는다면 [BRETT]을 참고하십시오.
빠른 Python 프로그램이 필요하시면 대신 PyPy JIT를 사용하십시오.
| [BRETT] | Brett Cannon, Localized Type Inference of Atomic Types in Python, http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.90.3231 |
이 RPython 언어는 무엇입니까?¶
RPython은 Python 언어의 제한된 부분집합입니다. RPython은 PyPy 툴체인 내에서 동적 언어 인터프리터를 구현하는 데 사용됩니다. 이러한 제약 덕분에 RPython 프로그램의 타입 추론(나아가 궁극적으로는 다른 언어로의 변환)이 가능해집니다.
“RPython이라는” 속성은 항상 개별 함수나 모듈이 아니라 프로그램 전체에 적용됩니다(변환 툴체인은 프로그램 전체를 분석합니다). 변환 툴체인은 모든 호출을 재귀적으로 따라가며 무엇이 프로그램에 속하고 무엇이 속하지 않는지를 알아냅니다.
RPython 프로그램의 제약은 대부분 타입을 임의로 섞어 쓰는 것을 제한합니다. RPython은 같은 변수에 서로 다른 두 타입을 바인딩하는 것을 허용하지 않습니다. 이런 점에서(그리고 몇몇 다른 점에서도) RPython은 Java와 다소 비슷하게 느껴집니다. RPython에서 허용되지 않는 그 밖의 기능으로는 __init__ 및 __del__을 제외한 특수 메서드(__xxx__)의 사용과 리플렉션 기능(예: __dict__)의 사용이 있습니다.
RPython에서는 기존 표준 라이브러리 모듈 대부분을 사용할 수 없습니다. 단, 네이티브로 지원되는 os, math, time의 일부 함수는 예외입니다.
RPython의 제약 사항에 대해 더 알아보려면 RPython 설명을 읽으십시오.
RPython은 Zope의 Restricted Python과 관련이 있습니까?¶
아닙니다. Zope’s RestrictedPython은 CPython을 위한 샌드박스 실행 환경을 제공하는 것을 목표로 합니다. PyPy’s RPython은 동적 언어 인터프리터를 구현하는 데 쓰이는 언어입니다. 그러나 PyPy는 견고한 sandboxed Python Interpreter도 제공합니다.
일부 독스트링에 보이는 "NOT_RPYTHON"은 무엇입니까?¶
함수의 독스트링에 “NOT_RPYTHON”을 넣어 두면, RPython 프로그램을 변환하는 도중 해당 함수가 발견될 경우 변환 과정이 중단되고 이를 오류로 보고합니다. 따라서 함수를 “NOT_RPYTHON”으로 표시하여 해당 함수가 절대 분석되지 않도록 할 수 있습니다.
함수를 RPython이 아닌 것으로 표시하는 이 방법은 더 이상 권장되지 않습니다. 새 코드에서는 대신 @objectmodel.not_rpython 데코레이터를 사용하십시오.
그냥 Python 구문 트리를 가져다가 Lisp로 바꾸면 되지 않겠습니까?¶
꼭 터무니없는 것은 아니지만, 진정한 PyPy 방식(The PyPy Way)이라고 하기는 어렵습니다. 어떤 형태로든 타입 추론이 없다면, 이 Python을 변환하기는 상당히 어렵습니다.:
a + b
이 Common Lisp보다 훨씬 더 효율적인 무언가로:
(py:add a b)
그리고 타입 추론을 가능하게 하는 것이야말로 RPython의 핵심입니다.
#'py:add를 제네릭 함수로 만든 다음, 주어진 CLOS 구현이 쓸 만한 속도를 낼 만큼 빠른지 확인해 볼 수도 있습니다(하지만 그 전에 강제 변환 규칙 때문에 아마 미쳐 버리게 될 것이라고 생각합니다). – mwh
제 프로그램을 RPython으로 다시 작성해야 합니까?¶
아니요, 시도하지 않는 것이 좋습니다. 무엇보다도 RPython은 인터프리터를 작성하기 위해 설계된 언어입니다. RPython은 Python의 제한된 부분집합입니다. 여러분의 프로그램이 인터프리터가 아니면서 표준 Python 라이브러리의 어떤 부분이나 어떤 서드파티 라이브러리를 사용하는 것처럼 “실제 작업”을 하려 한다면, 그 프로그램은 애초에 RPython이 아닙니다. RPython은 직접 인터프리터를 작성하려는 경우에만 살펴보십시오.
Python 코드의 속도를 높이는 것이 목표라면 일반 PyPy를 살펴보십시오. PyPy는 Python 2.7을 완전히 준수하는 인터프리터이며, 공교롭게도 RPython으로 작성되어 있습니다. 코드를 RPython으로 다시 작성할 필요가 없을 뿐만 아니라, 설령 다시 작성하는 데 성공하더라도 속도가 전혀 향상되지 않을 수도 있습니다.
네, 충분히 노력하면 성능에 민감한 몇 가지 작업을 수행하는 작고 독립적인 RPython 코드 조각을 컴파일할 수 있습니다. 하지만 이런 경우는 저희에게 흥미롭지 않습니다. 코드를 RPython으로 다시 작성해야 했다면, 차라리 C나 C++ 또는 Java 같은 언어로 다시 작성해도 되었을 것입니다. 이들 언어는 훨씬 더 잘 지원되고, 문서화도 훨씬 더 잘 되어 있습니다 :-)
위 단락들이 진실의 전부는 아닙니다. 프로그램을 RPython으로 작성하면 PyPy 위에서 실행할 때보다 상당히 더 빠른 속도를 얻는 경우가 있다는 것은 분명 사실입니다. 하지만 PyPy를 이끄는 핵심 그룹의 태도는 “그렇다면 PyPy의 성능 버그로 보고해 주십시오!”라고 답하는 것입니다.
좀 더 완곡하게 표현하면 다음과 같습니다. 위의 “안 됩니다, 하지 마십시오!”는 새로 오신 분들께 드리는 일반적인 경고입니다. RPython은 그다지 단순하지도 않고 폭넓게 문서화되어 있지도 않으므로 이분들은 어딘가로부터 많은 도움을 받아야 할 가능성이 큽니다. 그러나 동시에 저희 PyPy 핵심 그룹은 동적 언어용 인터프리터와는 매우 다른 일을 하는 서드파티 프로젝트를 지원하는 데 시간을 투자할 생각이 없습니다 — 그저 저희에게는 다른 관심사가 있고 하루에 쓸 수 있는 시간이 한정되어 있기 때문입니다. 그래서 요약하자면, 새로 오신 분들께는 더 대중적이고 많은 사람에게서 도움을 받을 수 있는 기존의 대안을 안내해 드리는 것이 온당하다고 생각합니다.
그래도 누군가 진지하게 RPython을 널리 알리고 싶다면 얼마든지 그렇게 하셔도 됩니다. 저희는 그런 계획에 적극적으로 반대하지 않을 것입니다. 예를 들어 GIL에 기반하지 않은 멀티스레딩 지원을 비롯하여, RPython을 더 나은 Java 비슷한 언어로 만들기 위해 할 수 있는 일은 많습니다. 하지만 저희와는 거의 관련이 없기 때문에 저희는 그런 일들을 구현하지 않습니다. 이것은 오픈 소스이며, 이는 누구든 무엇이든 자유롭게 홍보하고 개발할 수 있다는 뜻입니다. 하지만 이는 또한 저희 스스로는 그 방향으로 나아가지 않기로 선택하는 것도 여러분이 받아들여야 한다는 뜻이기도 합니다.
RPython 툴체인에는 어떤 백엔드가 있습니까?¶
현재 유일한 백엔드는 C입니다. 이 백엔드는 PyPy 인터프리터 전체를 변환할 수 있습니다. 백엔드에 대해 더 알아보려면 변환 문서를 참고하십시오.
LLVM을 사용할 수 있습니까?¶
이론상으로는 그렇습니다. 하지만 저희는 이미 이것을 변환 백엔드나 JIT 백엔드로 5~6번 사용해 보았으나 — 매번 실패했습니다.
좀 더 자세히 설명하면, 요즘에는 C 코드를 생성해서 clang으로 컴파일할 수 있으므로 LLVM을 (정적) 변환 백엔드로 사용하는 것은 의미가 없습니다. (PyPy를 clang으로 컴파일해도 gcc로 컴파일한 것보다 빠른 결과를 얻지는 못한다는 점에 유의하십시오.) 이론적으로는 LLVM의 GC 통합에서 추가적인 이점을 얻을 수도 있지만, 조금이라도 쓸모가 있으려면 먼저 LLVM 쪽에서 더 많은 작업이 이루어져야 합니다. 어쨌든 이는 C 코드의 사용자 정의 프리미티브를 통해 연결할 수 있을 것입니다. (이러한 실험적 백엔드 중 가장 최근의 것은 llvm-translation-backend 브랜치에 있으며, Linux에서 JIT를 포함하거나 포함하지 않은 상태로 PyPy를 변환할 수 있습니다.)
한편, LLVM을 JIT 백엔드로 사용하는 것도 흥미로워 보입니다 — 하지만 이 역시 시도해 보았고 실패했습니다. LLVM에는 생성된 기계어 코드를 패치할 방법이 없으며, 트레이싱 JIT에는 전혀 적합하지 않습니다. LLVM을 사용하려던 대형 메서드 JIT 하나조차 비슷한 이유로 포기했습니다. 자세한 내용은 해당 블로그 글을 읽어 보십시오.
따라서 PyPy 핵심 개발자들의 입장은 이렇습니다. 누구든 LLVM으로 N+1번째 시도를 해 보고 싶다면 환영하며, IRC 채널에서 약간의 도움도 받을 수 있습니다. 하지만 그것이 제대로 동작한다는 것은 시도하는 사람이 직접 입증해야 합니다.
PyPy 컴파일 시 스왑이 발생하거나 메모리가 부족해지는 경우¶
이 내용은 문서화되어 있습니다(여기와 여기). PyPy 위에서 “rpython targetpypystandalone”을 실행하려면 4 GB의 RAM이 필요하며, CPython 위에서 실행할 때는 조금 더 필요합니다. 사용 가능한 여유 메모리가 4 GB 미만이면 끝없이 스왑만 계속합니다(스왑 공간이 부족하면 실패합니다). 그리고 여기서 말하는 것은 여유 메모리입니다. 머신의 메모리가 총 4 GB라면 스왑이 발생합니다.
32비트에서는 이 수치를 절반으로 나누십시오. (최근에 시도해 보지는 않았지만, 예전에는 다른 프로그램을 전혀 실행하지 않은 상태라면 2 GB Linux 머신에서도 32비트 버전을 컴파일할 수 있었습니다. 예를 들어 Gnome/KDE도 실행하지 않은 상태였습니다.)
직접 만든 인터프리터는 어떻게 컴파일합니까?¶
Andrew Brown’s tutorial을 읽는 것부터 시작하십시오.
PyPy용 RPython 모듈을 독립적으로 변환할 수 있습니까?¶
아니요, 인터프리터 전체를 다시 빌드해야 합니다. 이는 두 가지를 의미합니다.
- 테스트 주도 개발을 반드시 사용해야 합니다. 모듈을 변환해 보기도 전에 먼저 순수 Python에서 모듈을 철저하게 테스트해야 합니다. 모듈을 변환하고 나면 고쳐야 할 타입 문제가 몇 가지만 남아 있어야 하며, 그 밖에는 결과물이 별도의 작업 없이 바로 동작해야 합니다.
- 둘째로, 그리고 아마도 가장 중요한 점으로, 애초에 그 모듈을 RPython으로 작성해야 할 정말 타당한 이유가 있습니까? 요즘에는 순수 Python으로 작성하고 C 코드를 호출해야 한다면 cffi를 사용하는 것과 같은 대안을 꼭 검토해 보아야 합니다.
이 맥락에서는 RPython 모듈을 전체 인터프리터의 변환과 별개로 변환할 수 있는지가 그리 중요하지 않습니다. (충분한 노력을 들이면 가능하겠지만, 이는 정말 만만치 않은 작업입니다. 당분간은 실현될 가능성이 매우 낮은 일로 생각하십시오.)
변환기는 왜 변환 도중에 만델브로 프랙털을 그립니까?¶
재미있기 때문입니다.