SIRINI`s Blog

life, saying, developing, . . . and so on

파이썬은 느려도 늦지 않다

요즘 회사에서 제 업무 목적으로 파이썬을 부쩍 많이 쓰기 시작했습니다. 늦게 배운 도둑질...아니 코딩질이(?)이 더 무섭다고, 처음에 접했던 PHP 보다 더 좋아지고 있습니다. 이러다가 GR Board 3 부터는 파이썬으로 개발하게 될 지도 모르겠다는 생각이 듭니다. (여담이지만 GR Board 2 정식 버전은 올해 안에 출시 할 수 있을런지... -ㅁ-)

데이터 분석 목적으로 처음에는 C++ 과 MFC 가 혼재된 환경에서 분석용 알고리즘을 만들고 이를 개선해 왔는데, 이게 파일 기반인데다가 다루는 파일 자체도 그리 많지 않아서 스크립트 언어를 이용해서 프로토타이핑을 해보고, 그럭 저럭 괜찮다 싶으면 별도로 C++ 기반으로 옮기지 않고 그냥 그대로 써도 괜찮을 것 같다는 생각이 요즘 들어 갑자기 강하게 들었습니다. 올해 들어 파이썬 언어에 매료되어 책도 사서 보고 이것 저것 필요한 기능들을 조금씩 구현해 보고 있었는데 한 3개월 정도 열나게 해서 그런가 이제 좀 나름의 자신감(?!)이 붙은 것 같습니다. ㅎㅎ;

오늘도 다른 날과 마찬가지로 뭔가 기능을 구현하기 위해서 일단 파이썬으로 프로토타이핑을 해 보았습니다. 간단하게 설명하면 바이너리 파일들이 있는데 그 것들은 전체적으로 보면 균일한 패턴을 가진 값들로 채워 집니다. 그 중에서 일부 튀는 값들을 찾아 해당 값과 좌표 등을 얻어내는, 어떻게 보면 아주 단순한 작업입니다.

처음은 아주 심플하게 구현해 보았습니다. with open(filePath, 'rb') as f: f.read(2) ... 이런 식으로 C 스타일로 먼저 작성을 시작했습니다. 대충 작성해서 동작 시켜 보고 값이 의도한 대로 나오는지 확인했고, 다행히(!) 훌륭하게 동작 되었습니다. 단지 역시나 허접 파이썬 초보인 제가 작성 하다보니 속도가 어마무시하게 느렸습니다. 데이터들이 C언어로 표현하자면 unsigned int 단위로 들어가 있는데 이를 파이썬에서 일일히 bit shift 하고 bit OR 연산 쓰고 하면서 엔디안을 맞춰주다보니 그거 하는데만도 시간을 많이 잡아 먹더라구요.

그래서 에이 그러면 그렇지 하고 C++ 로 바로 넘어 가려다, 뭔가 numpy 를 설치하지 않고도 간단하면서 빠르게 해결할 수 있는 방법이 이미 있지 않을까 싶어 조금 검색해 보았더니 바로 이게 있는 겁니다! array 모듈! (https://docs.python.org/3.4/library/array.html)

아... 뭔가 머리를 한 대 맞은 듯한 느낌이 들었습니다. 다시 코드를 좀 더 수정해서, 파일을 열어서 엔디안을 맞추는 부분을 다 빼 버리고 아래와 같이 개선해 보았습니다.



그랬더니 C++ 을 쓰는 거랑 별 다른 차이 없이도 속도 개선이 비약적으로 되는 겁니다! 순전히 제가 무식한 탓에 제대로 구현하지 못해서 파이썬은 그냥 느리다는 편견을 가지고 있었던 것이었습니다. 물론 실시간성이 보장 되어야 하는 분야에서는 아직 제대로된 성능이 나오지 않지만 (이 분야는 C와 어셈블리가 지배하는 영역이니까요...!) 위에서 언급한 것 처럼 그냥 파일들을 다루는 것 정도는 조금만 신경 쓰면 제대로 된 성능이 나오는 걸 확인 했습니다.

아 하지만 사람 욕심 이라는 게 여기서 끝내지를 못하더군요. 좀 더 개선하고 싶다는 생각이 들었습니다. 이제는 오기로라도 C++ 로 가지말고 파이썬으로 뭔가 극대화된 성능을 내보자는 욕심에 이것 저것 고민을 해 보다가, 문득 주워 들은 Multiprocessing 모듈이 생각 났습니다! (https://docs.python.org/3.4/library/multiprocessing.html)

기억 하기로 파이썬의 GIL 때문에 Thread 보다는 차라리 Process 를 늘려 가는 방식으로 병렬 프로그램을 구현 하는 게 좋다는 조언이 기억 났습니다. 일단 저는 잘 모르니까 실험을 위해, Thread 로 먼저 구현을 해 보고 이어서 Process 를 늘려 가는 방식으로 구현을 해서 테스트를 해 보았습니다.

테스트를 위해 코드를 좀 더 개량 했습니다. 먼저 import threading 후 앞서 파일 개개별로 테스트를 수행하는 부분을 함수로 선언하고, 파일 1개 당 Thread 1개를 할당하여 총 10개의 Thread 를 .start() 하고 결과를 .join() 으로 기다려서 실행해 보았습니다. 혹시나 이미 파이썬을 잘 아시는 분들이 보시면 무슨 해괴 망측한 짓이냐고 꾸짖으실지 모르겠지만 일단 궁금 했습니다. 정말 성능이 제대로 나오지 않는 것인지... 정말 안 나오더군요. 차라리 Thread 를 안 쓰는 게 나을 것 같다는 생각이 스물스물 피어 올랐습니다. 

이번에는 from multiprocessing import Process 을 하고 Thread(target=func) 부분을 Process 로 바꿔서 테스트를 진행해 보았습니다. 마찬가지로 총 10개의 프로세스가 생성 되도록 해 보았는데, 순식간에 CPU 점유율이 100% 까지 치솟으면서 미친듯이 연산 하기 시작했습니다! 와우! 그리고 놀랍게도 정말로 기존 연산 속도에 비해서 거진 7~8배의 속도 향상이 있었습니다! C++ 을 이용하여 구현했던 것 보다 이게 훨씬 더 빠른 결과를 이끌어낸 것입니다! 아아... 정말 파이썬 너란 녀석... 크흐...!!!

다행히(?) 제가 도전했던 부분은 파일 단위로 연산이 일어나고 서로 연산이 거의 완전히 독립적이었습니다. 그래서 사실 병렬 프로그래밍을 구현하기에 더 없이 적합했던 것 같고 C++ 에서도 제대로 구현 했다면 마찬가지 이득이 있었을 겁니다. 하지만 중요한 건 파이썬으로 프로토타이핑을 한 것인데 속도가 정말 괜찮게 나왔고 더불어 개발 시간도 비교할 수 없을 정도로 빨랐다는 점입니다. 저 같은 허접 코더가 같은 양의 일을 해야 했다면 족히 4~5시간은 넘게 걸렸을 일이 30분 정도 뚝딱뚝딱 한 것으로 해결이 되니 이게 바로 파이썬이 주는 매력이 아닐까 싶습니다.

무슨 종교 간증(?) 같은 글을 남기게 되었는데 아무튼 결론은 파이썬은 느리지만 느리지 않다는 겁니다. 스크립트 언어이고 인터프린터의 태생적 한계로 어쩔 수 없이 느린 부분이 있긴 하지만, 경우에 따라서는 꽤 괜찮은 속도로도 동작 할 수 있다는 걸 알게 되었습니다. 그리고 무엇 보다도 중요한 개발 속도를 정말 확실하게 보장해 준다는 믿음이 생겼습니다. 생각나는 대로 코딩 → 파이썬 내장 모듈 활용 → 병렬 프로그래밍 적용까지 코드를 개선 하는데 그리 많은 시간이 걸리지 않았다는 걸 떠올려보면, 정말 나는 왜 이런 좋은 언어를 이제서야 알게 되었나 하는 생각까지 들 정도 입니다.

파이썬은 느려도 늦지 않습니다. 어쩌면 생각이 느린 걸 지도 모릅니다. 앞으로 더더욱 파이썬을 적극적으로 활용해 봐야 겠습니다. :^D

그렇세 시리니님은 파이썬이 되는 서버를 찾아 다니게 되시고..(...
Django 를 배워야 할 것 같습니다 ㅋㅋㅋ 근데 아직은 웹 서버 사이드로 PHP 가 저는 좋네요 ㅋ HHVM 을 통해서 퍼포먼스 개선을 해보고 싶기도 하고 나름 애정이 남아 있습니다. 하지만 파이썬이 출동하면 어떨까? 하는 생각에 가끔 혹합니다 ㅎㅎㅎㅎ
Leave a comment here!
이 곳에 이름(닉네임)을 입력하세요
이 곳에 글 수정/삭제를 위한 비밀번호를 입력하세요
이 곳에 이메일 주소를 입력하세요 (선택)
이 곳에 웹사이트 주소를 입력하세요 (선택)