[include(틀:다른 뜻1, from=파이파이, other1=엔드로~!의 등장인물, rd1=파이 파이, other2=냥코 대전쟁의 캐릭터 파이파이, rd2=레드 바스터즈)] [[파일:pypy-logo.svg|align=center&bgcolor=#fff]] PyPy의 상징인 [[우로보로스]] 로고. [목차] [[https://pypy.org/|PyPy 프로젝트 사이트]] == 개요 == 2007년에 처음 발표된 [[Python]]의 언어 구현 중 하나로, [[C언어|C]]로 짜인 기존의 CPython과 달리 '''Python으로 Python을 만드는 프로젝트'''이다.[* [[부트스트래핑]]이라고 한다.] 여기만 보면 뭔가 이상한 짓 하는 프로젝트 내지 실험적인 프로젝트처럼 느껴지겠지만, 이 프로젝트의 진짜 놀라운 점은 기존 CPython보다 전혀 느리지 않을 뿐더러, '''오히려 성능면에서 CPython을 능가하고 있다는 점이다.''' 나아가 [[https://speed.pypy.org/|이 링크]]에서 보이는 대로, '''계속해서 빨라지고 있다!''' 표준 구현인 CPython과의 속도비교. PyPy를 개발하면서 지속적으로 업데이트 하고 있다. == 상세 == PyPy는 단순히 Python을 가지고 장난을 하려고 시작한 프로젝트가 아니다. [[https://psyco.sourceforge.net/|Psyco]]라고 하는, 기존 파이썬 위에다가 [[JIT|Just-In-Time]] 컴파일을 구현해서 실행성능을 높이는 프로젝트가 있었는데, 이걸 개발하던 Armin Rigo라는 사람이 아예 JIT 컴파일을 하는 파이썬을 처음부터 다시 구현하기로 생각했다. 그래서 2003년부터 PyPy 개발을 시작하여 [[유럽연합]]의 연구자금 지원을 받아가며 지금도 개발하고 있다. == 어떻게 구현하나 == [[인터프리터]] 방식의 [[Python]]을 가지고 파이썬으로 돌리는 파이썬을 어떻게 만들었을까. PyPy의 접근법은 이렇다. 1. 먼저 RPython이라고 하는, 파이썬 문법을 엄격하게 만들어 컴파일이 되게 만든 해석기(translate.py)를 Python 코드로 작성한다.[* RPython는 Python의 일부만 구현한 언어(부분 언어)이기 때문에 모든 RPython 코드는 Python 코드이기도 하다. (반대는 성립하지 않는다.)] 1. RPython의 효과적인 컴파일을 위해 다른 언어로 툴체인을 만든다.[* [[시뮬레이터]]나 [[에뮬레이터]]를 제작하는 때에도 이 과정을 반드시 거친다.] 1. Python 구현(런타임)을 RPython 문법으로 작성한다. 1. 3에서 만든 구현을 1 또는 2에서 만든 RPython 해석기로 컴파일한다. 1. 4으로 만든 후보를 이전 또는 다른 구현과 비교(성능 측정), 만족스럽지 않으면 수정한다.(nightly builds) 1. 5에서 만족스러운 결과를 냈다면 출시하고 1 또는 2부터 다시 시작한다.(release) 처음 한번만 기존 파이썬의 도움을 받으면 그 다음부터는 스스로 만든 구현으로 저 과정을 자체적으로 계속 반복할 수 있다. 이러한 이유로 로고가 [[우로보로스#s-1]]인 셈. 이게 얼핏 보면 '[[닭이 먼저냐 달걀이 먼저냐]]' 같은 것으로 착각할 수도 있지만, 이런 식의 접근법은 실제로 프로그래밍 언어를 제작할 때 해당되는 사항이다. 일례로 오래 전에 만들어진 유명 C/C++ 컴파일러인 [[GCC]]도 C/C++로 작성되었다. 파이썬이 스크립팅 언어이기 때문에 일견 특이해보이는 것일 뿐, 인터프리터는 어차피 컴파일된 상태로 돌아가므로 같은 원리다.간단히 보자면 더 좋은 장비의 개발을 위해 기존의 장비를 사용하는 것과 다름이 없다. 짱돌로 뗀석기를 만들고, 뗀석기로 간석기를 만들었던 것 처럼 '''인류 역사에 고고히 전해져오는 방법론''' 을 사용하고 있는 것이다. 이런 식으로 어떤 언어로 자기 자신을 구현하는 것을 '''부트스트래핑'''(Bootstrapping) 또는 '''부팅'''(Booting)[* 운영체제의 부팅과 같은 어원으로, [[뮌히하우젠 남작]]의 모험 이야기에서 유래했다.]이라고 하는데, 이렇게 하는 이유는 처음부터 작업하는 것보다 생산성이 좋기 때문이다. 처음부터 어셈블리어로 작업하면 [[이론상 최강]]의 성능을 발휘할 수는 있으나 그 가능성은 매우 낮고 생산성도 최악이다.([[최적화]]가 그래서 힘들다.) 이 때문에 대부분의 프로그래밍 언어도 초창기에는 어셈블리어나 다른 고급언어의 도움을 받지만, 일정 단계를 넘어서면서 발전에 한계가 오면 스스로의 컴파일러/인터프리터를 제작하게 된다. Haskell 컴파일러인 GHC와 C/C++ 컴파일러인 GCC가 대표적인 예. 물론 생산성에 중점을 두기 때문에 성능이 눈에 띄게 빨라지는 일은 드물고, 단지 우연한 발견 등 여러 이유로 성능이 향상되는 것 뿐이다. PyPy의 경우 Python의 한계를 극복하기 위해 정적인 컴파일이 가능한 RPython을 따로 만들었고 뒤에도 후술한 것처럼 성능 향상을 위해 '''7년이라는 긴 세월'''을 소모했는데, 이것도 어셈블리어로 처음부터 개발하는 것보다는 짧은 것이다.[* 컴퓨터 하드웨어의 발전도 마찬가지다. 처음 IC나 LSI를 설계할 때는 레이아웃을 손으로 그렸지만, 지금 나오는 칩들은 손으로 하기에는 회로의 규모가 지나치게 크기 때문에 전부 CAD로 개발하고 있다.] == JIT, 그리고 마개조 == PyPy는 RPython으로 이루어진 Python 인터프리터와 (역시 RPython으로 이루어진) C, .Net, JVM 등을 타게팅한 해석 툴체인으로 이루어져 있는데, 해석 툴체인은 해당 플랫폼을 위한 효율적인 코드를 생성하는 데 초점이 맞춰져 있으며, Tracing JIT을 통해 인터프리터 단위의 [[JIT]] 컴파일이 가능하므로, CPython보다 빠른 결과물이 나오게 된다. 여기까지만이어도 그냥 기존 구현보다 그다지 느리지 않은 파이썬 구현을 다른 언어의 도움 없이 파이썬 스스로 만든 셈이지만, 여기서 하나가 더 들어간다. Armin Rigo가 뭐 만들던 사람이라는 내용이 위에도 있지만 PyPy는 [[JIT]] compiler이다. 그것도 그냥 JIT가 아니라 Meta tracing JIT라는 괴랄한 것을 구현했는데, JIT이 필요한 부분에 약간의 힌트 코드를 넣으면 '''RPython 해석기가 알아서 JIT compile이 되는 언어 구현을 만들어준다.''' 다른 언어 구현들이 JIT 좀 해보자고 무지막지한 삽질을 하는 것과 달리[* 인터프리트나 바이트코드 컴파일 방식을 가지는 언어 구현 사이에 [[JIT]]를 실용적으로 하는 구현은 [[Java Virtual Machine|JVM]]이나 [[Microsoft .NET#Framework|.NET Framework|.NET CLR]] 정도밖에 없다. [[오라클(기업)|둘]] [[마이크로소프트|다]] 돈 좀 쓰고 다닐 것 같은 느낌이 들지 않는가?] 거의 공짜와 다름없다. 하지만, 사실 만들고 나서 보니 그렇게 보이는 거고 PyPy는 그냥 JIT를 구현한 게 아니라 '''JIT 구현을 만들어주는 컴파일러를 구현'''한 셈이 되므로 실제 작업은 훨씬 더 어려웠을 것이다. 당장 PyPy가 CPython보다 빨라진 게 PyPy 1.3부터인데, [[https://morepypy.blogspot.com/2010/06/pypy-13-released.html|그게 2010년 중순이다.]][* 위에도 있지만 '''2003년에 개발을 시작했다.'''] 다시 말해, 7년 동안 아무도 알아주지 않던 '진화'가 드디어 빛을 본 셈. 그리고 본인들도 [[https://morepypy.blogspot.com/2010/12/we-are-not-heroes-just-very-patient.html|"우리는 영웅이 아니며, 단지 인내심이 많았을 뿐이다."]]라고 말하고 있다. 잠시 PyPy 개발팀의 근성에 경의를 표하자. 여담으로, 이 녀석의 해석은 사람만 힘드는 게 아니라 컴퓨터도 힘든 모양이다. 써 볼 사람들은 --시간이 남아돌고-- 사용하는 컴퓨터가 어지간히 고사양이 아니라면 미리 컴파일된 것을 받아 사용하자. CPython을 통한 Bootstrapping에 엄청난 시간과 메모리를 요구한다 [[준비물]]이 모두 갖춰진 상태에서 PyPy 2.2.1 달랑 하나를 빌드하는 데에 [[모질라 파이어폭스]]와 그것이 의존하는 모든 다른 패키지들을 빌드하는 것보다 시간이 더 걸린다! '''Core i7 3.33GHz, 다른 작업 방해 없이 코어 1개 풀사용, 8GB 램''' 기준으로 '''최소 3시간'''은 각오해야 한다. 64비트 CPython으로 컴파일하다 보면 Python 프로세스 하나가 램을 5GB 가까이 [[처묵처묵]]하는 것도 볼 수 있다. 그래도 이런 구조로 만든 [[덕분]]에 보너스로, RPython 컴파일을 할 때 목적 타겟을 다르게 주면 다른 플랫폼으로도 돌아가는 파이썬 구현이 나오고, 똑같은 PyPy 소스코드로 [[Python|CPython]] 같은 것도 나오며, [[Java|Jython]] 같은 것도, [[Microsoft .NET#Framework|IronPython]] 같은 것도 나온다. 추가로 [[코루틴]]을 쓰는 Stackless Python 같은 것도 비슷한 방법으로 만들 수 있어서 Stackless Python 개발하던 Christian Tismer가 아예 PyPy 개발팀에서 같이 일하고 있다.[* 여담이지만 [[https://bitbucket.org/ambroff/greenlet/src/77363116e78d/AUTHORS|이 두 사람이 모여서 만든]] 또 하나의 작품이 [[https://pypi.python.org/pypi/greenlet|greenlet]]인데, Psyco처럼 기존의 CPython에다가 [[마개조]]를 해서 원래 지원 안 되는 코루틴을 만들어 올리는 라이브러리다... [[https://lee-seungjae.github.io/greenlet.html|참고]]. 추가적으로, 코루틴은 파이썬 3.4부터 내장되며, 3.5부터는 async과 await이라는 키워드도 탑재된다.] == 호환성 == PyPy 개발팀의 호환성 기준은 매우 심플해서, '''이유 여하를 막론하고 CPython에서 되는 게 PyPy에서 안 되면 그냥 PyPy 버그'''다. 예전에는 PyPy는 구조적 문제로 인해서 64비트 윈도우용으로 컴파일 할 수 없었다. 물론 32비트용으로는 제공되므로 윈도우와의 호환성에 큰 문제가 되지는 않는다. 하지만 3.7 버전부터 문제를 해결해 64비트 윈도우로도 배포한다. [[https://doc.pypy.org/en/latest/windows64.html|#]] == 예제 == [[몬티 홀 문제]]로 테스트 해 보자. {{{#!syntax python import time import random def populate_doors(): # put a car behind one door door=['goat', 'goat', 'goat'] door[random.randint(0,2)]='car' return door wins = 0 losses = 0 time_start = time.time() # playing the game 100,000 times: for x in range(100000): doors=populate_doors() first_choice=random.randint(0,2) # choose a random door for y in range(3): # reveal first losing, unchosen door if doors[y] != 'car' and y != first_choice: doors[y] = 'out' break if doors[first_choice] == 'car': losses = losses + 1 # contestant switched to losing door else: wins = wins + 1 # contestant switched to winning door time_finish = time.time() print("All choices were switched.") print("Wins: ", wins) print("Losses: ", losses) print("Elapsed time: ", time_finish-time_start) }}} 코드 출처[* 현재 불능 [[http://www.danielveazey.com/tag/monty-hall-problem/]], 가장 유사한 곳 [[https://matthew-brett.github.io/dsfe/chapters/extra/monty_hall_lists]]] PyPy가 약 '''25'''배[* Python 2.7.11 x86_64, PyPy 5.1.0 x86_64 기준.] 빠르다. 물론 코드에 따라 배율에 차이가 있고 가끔씩 더 느린 코드도 있지만 어지간한 경우엔 PyPy쪽이 빠르다.[* 2021년 시스템 64비트, pypy 3.7.9와 python 3.9.2로 측정결과, pypy가 거의 2배 정도 빠름] [[분류:시스템 소프트웨어]][[분류:Python]]