본문 바로가기

IBM CampusWizard/developerWorks

Psyco로 파이썬을 C 만큼 빠르게!


글의 출처는 IBM dW입니다.

IBM developerWorks.
Charming Python : Psyco로 파이썬을 C 만큼 빠르게!

Psyco (파이썬 컴파일러)

난이도 : 초급

David Mertz, Ph.D., 프리랜스 작가, Gnosis Software, Inc

2002 년 10 월 01 일

어떤 면에서 파이썬 디자인은 자바 디자인과 닮았다. 두 개 모두 가상으로 컴파일된 바이트코드를 인터프리팅하는 가상 머신을 사용한다. JVM이 파이썬보다 나은 것은 바이트코드의 실행을 최적화하는데 있다. 파이썬 컴파일러인 Psyco이 이러한 차이를 줄이는데 도움이 될 것이다. 현재 Psyco는 외부 모듈이지만 언젠가는 파이썬에 포함 될 것이다.

파이썬은 웬만큼 빠르다. 파이썬 같은 인터프리팅/바이트-컴파일 언어의 실행 속도에 대해 미숙한 프로그래머가 표현하는 걱정의 90%는 순진하다. 요즘의 하드웨어에서 대부분의 최적화 되지 않은 파이썬 프로그램들은 충분히 빠르게 실행된다. 애플리케이션을 빠르게 만들고자 하는 가외의 프로그래밍 노력을 할 필요가 없다.

파이썬 프로그램의 속도를 높일 수 있는 많은 방법이 있다. 대부분의 개발자의 머리속에 떠오르는 그 첫 번째 기술은 알고리즘과 데이터 구조를 향상시키는 것이다. 비효율적인 알고리즘의 단계들을 최적화하는 것은 헛된일이다. 어셈블리에서 재작성하는 것도 마찬가지이다.

가장 먼저 고려해야할 두 번째 기술은 파이썬 애플리케이션을 프로파일링 하는 것이다. SWIG 같은 확장 래퍼를 사용하여 C 코드처럼 프로그램의 엘리먼트를 실행하는 C 확장을 만들 수 있다. 이런 방식을 사용하여 파이썬을 확장하는것은 비교적 간단하다. 하지만 배우는데는 시간이 걸린다.

세 번째 기술은 두 번째 기술을 기반으로 한다. Greg Ewing은 Pyrex라고 하는 언어를 만들었는데 이것은 파이썬과 C를 혼합한 것이다. 특히 Pyrex를 사용하기 위해서는 선택된 변수에 유형(type) 선언을 추가하는 파이썬 계열의 언어에 함수를 작성한다. Pyrex(툴)은 ".pyx" 파일을 ".c" 확장으로 처리한다. C 컴파일러로 컴파일되면 이 Pyrex(언어) 모듈은 파이썬 애플리케이션에 반입되어 사용될 수 있다. Pyrex가 파이썬과 같은 신택스를 사용하기 때문에 Pyrex 프로그래머는 확장을 작성하기위해 C를 배울 필요가 없다. 더욱이 Pyrex는 C 레벨 변수와 파이썬 레벨 변수를 같은 코드 내에서 완벽하게 혼합한다.

마지막 기술이 바로 이 글의 주제이다. 확장 모듈인 Psyco는 파이썬 인터프리터의 중심에 플러그인 될 수 있다. 그리고 파이썬의 인터프리팅 된 바이트코드 부분들을 최적화된 머신 코드로 대체한다. 위에 열거한 다른 기술들과는 다르게 Psyco는 파이썬 런타임을 철저하게 지켜 작동한다. 다시말해서 파이썬 소스 코드는 python 명령어에 의해 정확히 전과 같은 방식으로 바이트코드로 컴파일된다. 파이썬 인터프리터가 애플리케이션을 실행하고 있는 동안, Psyco는 정식 파이썬 바이트코드 액션을 대신하여 특별한 머신 코드를 대체할 수 있는지의 여부를 검토한다. 이 특별한 컴파일은 자바의 just-in-time 컴파일러의 방식과 매우 비슷하며 아키텍쳐 전용이다. 지금 Psyco는 i386 CPU에서만 가능하다. Psyco의 장점은 언제나 작성해오던 파이썬 코드를 사용할 수 있다는 점이고 빠르기는 훨씬 빠르다는 점이다



위로

Psyco 작동 방법

Psyco를 완전히 이해하려면 파이썬 인터프리터의 eval_frame() 함수와 i386 Assembly를 알아야한다. 불행히 나는 그 두 가지 모두를 완벽히 설명할 수 없지만 Psyco는 잘 설명할 수 있다.

정식 파이썬에서 eval_frame() 함수는 파이썬 인터프리터의 내부 루프(loop)이다. 기본적으로 eval_frame() 함수는 실행 콘텍스트에서 현재의 바이트코드를 보고 콘트롤을 바이트코드 실행에 적합한 함수로 변환한다. 이것의 함수 지원 특징은 메모리에 저장된 다양한 파이썬 객체의 상태에 의존한다는 것이다.

Psyco는 eval_frame() 함수를 복합적인 평가 유닛으로 대체한다. Psyco가 파이썬을 향상시킬 수 있는 여러 방법이 있다. 우선 Psyco는 오퍼레이션을 최적화된 머신 코드 어딘가에 컴파일한다. 이 자체로 약간의 향상을 보인것이다. 왜냐하면 머신 코드에 필요한 것은 파이썬의 함수들이 하는 것과 같은 것을 수행하는 것이기 때문이다. 아래 코드에서 변수 x는 루프 실행동안 알 수 있다:


x = 5
l = []
for i in range(1000):
    l.append(x*i)

이 코드의 최적화 코드는 "x 변수/객체의 콘텐트"에 의해 각 i를 멀티플라이 할 필요 없다.

작은 오퍼레이션을 위해 i386 스팩의 코드를 만드는 것 외에도 Psyco는 나중에 다시 사용할 목적으로 이 컴파일된 머신을 보관한다. Psyco가 특정 작동이 이전에 일어난 것과 같다는 것을 인식할 수 있다면 캐시된 코드에 의존할 수 있다.

Psyco의 진짜 장점은 오퍼리이션의 카테고리를 세 가지 다른 레벨로 한다. Psyco에는 "런타임(run-time)", "컴파일 타임(compile-time)","가상 타임(virtual-time)" 변수들이 있다. Psyco는 필요할 때 레벨 간 변수를 승격/강등 시킨다. 런타임 변수는 미가공 바이트코드이고 정식 파이썬 인터프리터가 핸들하는 객체 구조이다. 컴파일 타임 변수는 머신 레지스터에 나타나고 메모리 로케이션에 직접 접근된다.

가장 재미있는 것은 가상 타임 변수이다. 내부적으로 파이썬 변수는 많은 멤버를 갖고있는 완벽한 구조이다. Psyco 가상 타임 변수는 필요할 때 구현될 수 있는 파이썬 객체들을 말한다 :

x = 15 * (14 + (13 - (12 / 11)))

표준 파이썬은 이 값을 계산하기 위해 많은 객체들을 구현하고 파괴한다. 전체 정수 객체는 (12/11)의 값을 갖기위해 구현된다. 그런다음 값은 임시 객체의 구조에서 빠져나오고 새로운 임시 객체인 (13-PyInt)를 계산하는데 사용된다. Psyco는 객체들을 건너뛰고 이 값들을 계산한다. 객체는 이 값에서 필요할 경우 만들어질 수 있다는 것을 알기 때문이다.




위로


Psyco 사용하기

Psyco를 설명하기는 비교적 어렵지만 사용하는 것은 훨씬 쉽다. 파이썬 함수와 클래스에 어떤 코드 변화도 필요없다.

Psyco가 해야할 일을 지정하는 두 가지 방법이 있다. 강제적 방법은 Psyco가 어디서나 "just-in-time" 작동하도록 하는 것이다. 이를 위해 다음의 라인들을 모듈의 상단에 놓아야한다:


import psyco ; psyco.jit() 
from psyco.classes import *

첫 번째 라인은 Psyco가 모든 글로벌 함수에서 이 마법을 수행했음을 보여주고 있다. 두 번째 라인은 Psyco가 클래스 메소드와 같은 것을 수행했음을 보여주고 있다. Psyco의 작동을 좀더 자세히하려면 다음의 명령어를 사용한다:


psyco.bind(somefunc)          # or method, class
newname = psyco.proxy(func)

두 번째 형식은 func을 표준 파이썬 함수로 남겨둔다. 하지만 newname을 포함하는 호출을 최적화한다. 테스팅과 디버깅 이외의 모든 경우 psyco.bind()폼을 사용하게 될 것이다.




위로


Psyco의 퍼포먼스

Psyco가 마법같은 것 처럼 이를 사용하는데에도 약간의 생각과 테스트가 필요하다. 이해해야 할 점은 Psyco가 여러번 루핑하는 블록들을 핸들링하는데 유용하다는 것이다. 그리고 Psyco는 정수와 부동소수점 숫자를 포함하는 작동을 최적화하는 방법을 알고있다. 비 루핑 함수와 다른 유형의 객체에서 작동하는 경우, Psyco는 분석과 내부 컴파일을 위해 오버헤드를 추가한다. 게다가 많은 함수와 클래스를 갖고있는 애플리케이션의 경우, Psyco 애플리케이션을 실행하는데에는 머신 코드 컴파일과 캐싱용 메모리 사용에 많은 노력이 들어간다. 그러한 함수들을 선택적으로 바인딩하는것이 Psyco 최적화에 도움이 된다.

매우 단순한 방식으로 테스트를 시작하겠다. 최근에 사용하는 것 중 속도 향상을 고려하지 않고 있는 애플리케이션을 선택했다. 첫 번째 예제는 텍스트 조작 프로그램이다. 앞으로 출간될 내 책을 LaTex 포맷으로 변환하는데 사용하는 것이다. 이 애플리케이션은 스트링 메소드, 정규식, 정규식과 스트링 매치로 운영되는 프로그램 로직을 사용한다. Psyco 테스트에는 끔찍한 후보 이지만 그래도 시작해보겠다.

우선 psyco.jit() 을 스크립트 상단에 추가했다. 결과는 예상대로 실망스러웠다. 이 스크립트는 실행하는데 8.5초 걸렸다. 파이썬의 "스피드업" 후에는 12초가 걸렸다. just-in-time 컴파일은 시작 오버헤드를 갖고 있다. 그 다음으로 시도한것은 훨씬 큰 인풋 파일이다. 이것은 실행시간을 120초에서 110초로 줄이는 약간의 성공을 거두었다. 스피드업은 여러번 실행하여 일관성을 유지했다.

두 번째는 텍스트 프로세싱 후보이다. psyco.jit() 콜을 추가하는 대신 psyco.bind(main) 이라는 라인만 추가했다. main() 함수는 여러번 루핑하기 때문이다. 결과는 나아졌다. 이 접근방식은 일반 실행 시간에서 수십 초를 감소시켰다. 하지만 아직도 특별할 것은 없다.

좀더 신빙성있는 Psyco 테스트를 위해 neural network 코드를 선택했다. 이 "code_recognizer" 애플리케이션은 다른 프로그래밍 언어의 다양한 ASCII 값의 배포판을 인식하도록 훈련시킬 수 있다. 이는 파일 유형을 알아내는데 유용하다. 하지만 지극히 일반적이다. 이것은 얼굴, 소리, 주기적 패턴을 매우 쉽게 습득한다. "code_recognizer"는 파이썬 라이브러리인 bpnn에 의존한다. 이 글의 "code_recognizer"는 부동소수점 수학을 여러 번 루핑한다는 것과 실행에 많은 시간이 걸린다는 것을 알아야한다. Psyco 실행에 좋은 후보를 발견했다. .

이것 저것 테스트 한 후에 Psyco를 사용하는 방법에 대해 자세히 알게 되었다. 아주 적은 클래스와 함수를 갖고있는 이 애플리케이션의 경우 just-in-time을 사용하든 바인딩을 사용하든 큰 차이가 없다. 최상의 결과는 최적화할 수 있는 클래스를 선택적으로 바인딩할 때 이다. 하지만 Psyco 바인딩의 범위를 이해해야 한다.

code_recognizer.py 스크립트에는 다음의 라인이 포함되어 있다:


bpnn 에서 NN 반입하기
    
class NN2(NN): # customized output methods, math core inherited

Psyco의 관점에서 볼 때 재미있는 현상은 bpnn.NN이라는 클래스에 있다. psyco.jit() 또는 psyco.bind(NN2)code_recognizer.py 스크립트에 추가하면 작은 결과만 얻게된다. Psyco가 만족할 만큼 최적화를 수행하도록 하려면 psyco.bind(NN)code_recognizer.py에 추가하거나 psyco.jit()bpnn.py에 추가해야한다. 생각과는 다르게 just-in-time은 인스턴스가 만들어지거나 메소드가 실행될 때 발생하지 않지만 클래스가 정의되는 범위에서는 발생한다. 게다가 바인딩 의존 클래스는 아무데서나 상속된 메소드를 스페셜라이징 하지 않는다.

적절한 Psyco 바인딩의 세부사항이 만들어지면 결과 스피드업은 주목할 만하다. 반복을 10번으로 줄이면 그에 비례한 스피드업도 생긴다.

새 코드의 두 라인을 가지고 실행속도를 30분에서 10분으로 줄인것은 의미가 크다. 이러한 속도향상은 C의 비슷한 애플리케이션의 속도보다 빠르다.




위로


Psyco 현황

Psyco는 지금 현재 내부 통계나 프로파일링을 수행하지 않으며 단지 생성된 머신 코드의 최소한의 최적화만 수행한다. 다음 버전에서는 그 효과를 극대화하는 것을 목표로 만들어 질 것이다. 앞으로의 Psyco는 최적화 범위를 확대시킬 것이다.



참고자료

  • developerWorks worldwide 사이트에서 이 기사에 관한 영어원문.

  • Psyco's home page & project page : SourceForge.

  • Simplified Wrapper and Interface Generator (SWIG).

  • language Pyrex.

  • David와 Skaller 인터뷰 (developerWorks, October 2000).

  • Andrew Blais: An Introduction to neural networks (developerWorks, July 2001).

  • 리눅스 기술자료.


 

필자 의견 :
 
  사용 방법이 나와있기는 하지만 아직 실행해 보지는 못했습니다.. 나름 다른것들을 이것저것 만지다 보니.. 제대로 작동이 되는지는 모르겠네요 그것에 대해서는 직접 작동해본뒤에 추가로 글을 덧붙이겠습니다.
  그리고 psyco가 새로운 python 버전에는 추가가 되어 있을까 하고 알아봤는데 제가 발견 못한걸수도 있겠지만 최신버전인 2.5 버전까지는 아직 psyco가 추가 되지 않은 듯 합니다. 인터넷에서 psyco에 대해서 찾아보면 python을 사용하시는 대다수의 개발자들이 psyco를 같이 사용하고 있는거 같습니다. 사용평을 보면 다들 긍정적인 반응이고 최소4~최대100배 까지도 속도차이를 낼 수가 있다고 하더군요.  python을 사용하는 사람이라면 필수로 같이 사용해야할것이 psyco 인것 같습니다.