여러 프로세스로 분산해 주는 제너레이터

요새 인텔에서 80코어 CPU를 공개할 정도로 점점 병렬 프로세싱이 싼 가격과 작은 크기로 내려올 것 같은 분위기가 많이 돌고 있습니다. 저도 요즘 학교에서 하는 실험이 CPU 20개에 분산해서 실행해도 하루 정도 돌아가는 것이다 보니, 컨커런트 프로그래밍이 기본적으로 지원되는 언어들에 대한 소식에 요즘 상당히 솔깃 하고 있는데요. 으흐흐 하여간 파이썬은 GIL 때문에 여러모로 불안할 따름입니다;

그러던 중, 파이썬 마을에 어떤 분께서 작업을 N개의 프로세스로 분산해서 실행하는 방법을 질문해 오셔서 답글을 달다가, 예제로 만들어 본 것이 보고 있으려니 제너레이터로 만들면 상당히 깔끔해 질 것 같아서, 잠시 제너레이터로 만들어 봤습니다. 흐흐

긴 시간이 걸리는 같은 종류의 작업을 여러 데이터에 적용하는 경우를 가정하고 만든 것인데요, 우선 용례를 보면 이렇게 하면 좋겠다 생각이 들었습니다.

보통 이런 것들은 threads.start_new_thread()처럼 뒤에 함수를 줘서 그게 실행되는 경우가 많은데, 그러면 조그만 작업도 다 함수로 만들어야 해서 코드가 왔다갔다 해서 헷갈리죠. 그래서 for루프 안에 넣었는데, 실제로 for 안쪽이 여러 번 돌지는 않고, 각각이 별도의 프로세스로 최대 4개가 동시에 돌아가게 됩니다. 그래서 이 인터페이스에 맞게 구현해 보면 요렇게..

이렇게 만들고 나니, 왠지 결과 데이터를 메인 프로세스에 모두 모아오는 기능이나 프로세스 재활용 같은 기능도 넣어 보고 싶고 with 절로 해 보고 싶기도 했지만.. 일단은 돌아가기에 귀찮아서.. 흐흐 -ㅇ-;; with로 하는 경우에는 for와는 다르게 메인 프로세스에서 하위 블럭을 생략할 수 없어서 메인 프로세스도 일을 해야하다보니 좀 더 복잡하겠더군요..

그런데, 사실 이걸로 열심히 놀고보니, 원래 쓰던 셸 스크립트로 하는 방법이 훨씬 간단한 것 같아서 허탈합니다. 하하;;;; ㅡ.ㅜ

웹앱스콘에 오세요~

6월 21일(목요일)에 삼성동 코엑스에서 웹앱스콘 2007이 열립니다. 주제는 요새 흔히 있는 웹2.0의 종합선물세트이지만, 아마도 참가비도 매우 싸고 프로그램도 오랜 시간동안 업계의 많은 분들이 노력해서 조절한 덕에 알찬 행사가 될 것 같습니다. 🙂

저는 프레임워크 2.2 워크샵 트랙에서 김창준님과 함께 전반적인 진행을 맡을 예정인데, 지난번 프레임워크 2.1에서 예고했던 대로, 이만용이사님의 TurboGears, 김승범군의 Seaside 가이드가 있을 예정이고, 덧붙여서 김창준님과 여러 분들이 분산 프로그래밍 언어인 Erlang으로 실시간으로 웹 프레임워크를 만들어가는 과정을 보여드릴 예정입니다.

전반적인 흐름은 지난번과 비슷하지만, 이번에는 전체가 따라해보기로 실습할 예정이기 때문에 모두 노트북을 지참하셔야하는 제한이 있고요~ 이제 인원 제한이 얼마 안 남았으니 참여하실 분들은 얼른 신청하세요~ 🙂

대화하는 사람들의 닉네임으로 현재 시간 추측하기

평소에 IRC를 항상 켜놓고 생활하다보면 종종 굳이 시계를 보지 않아도 IRC에서 어떤 사람들이 떠들고 있는지만 봐도 대충 시간이 얼마쯤 되었겠구나 생각할 때가 있습니다. 창문과 가까이 자리가 있는 사람들은 밖에 사람들이 지나가는 방향만 봐도 대충 시간을 알 수 있고, 차가 많이 보이는 곳에 자리가 있는 사람들은 교통 상황을 봐도 대략 짐작할 수 있는 거나 마찬가지로요~

그래서, 과연 이게 그냥 기분탓인지 실제로 경향이 강해서 쓸만한 지표인지 시험해 보려고 지난 몇 개월간의 IRC로그를 분석해서 떠든 사람 이름(!)과 횟수를 가지고 시간을 1시간 단위로 추측하도록 한번 통계내어 보았습니다.

우선, 예측 방법은 요새 인기가 하늘을 날고 있는 random forest를 사용했는데,
R에 들어있는 randomForest
모듈을 사용하기로 했습니다. party 패키지가 좋다는 얘기도 있지만.. 매뉴얼이 허술해서 사용법을 터득하지 못한 관계로 –;;

데이터는 HanIRC의 #perky에서 우선 IRC 데이터를 1시간 단위로 각 닉네임 별로 대화한 횟수(줄 단위)를 해당 시간에 모든 사람이 말한 횟수에서 나눈 값을 뽑았는데, 이 방법으로 과열된 상황과 심심한 상황을 대략 평준화를 할 수 있을 것 같고.. 해당 시간의 입력 벡터에 해당 시간의 데이터 뿐만 아니라 이전, 이후 시간의 것도 넣어서 연속성으로 추측할 수 있게 했습니다. 그래서 총 20명의 데이터를 이전, 현재, 이후 3가지 해서 60개 + 전체 대화량 3개 해서 63개의 실수 벡터가 들어갔습니다.

채널에 참여하는 인원이 비정기적으로 들어오는 분들을 포함하면 200명이 넘기 때문에, 여기서 입력 샘플로 20명만 추려서 사용했습니다. 물론 그 기준은 어느 정도 생활 패턴이 일정하면서 대화량이 적지 않고, 대상 기간에 생활리듬이 급격하게 변할만한 사건이 없었던 것으로 추정되는 분들을 골랐지요. 🙂

그래서, 이제 간단한 스크립트(로그파서, 데이터 가공)로 데이터 가공을 끝내고 이제 R에서 읽어서 쭈욱 처리했습니다. 노트북에서 했는데도 그다지 오래 안 걸리네요. (트리 수는 디폴트가 500개)

3,5월 자료로 트레이닝해서, 4월 자료로 테스트를 해 보면 다음과 같은 예측값 히스토그램을 얻을 수 있었습니다.

이것 보면 대략 오전은 거의 2시간 내외 오차로 썩 잘 맞히는 것 같고, 오후는 제법 오류가 많습니다. 특히 실제로는 늦은 오후 자료인데, 그걸 새벽 데이터로 오인한 경우가 많네요. 그리고 한낮 자료를 늦은 오후로 오인한 경우도 많고요. 역시 IRC사람들이 오전엔 아주 일정한 생활을 하는 반면에 오후에는 많이 바뀌는 것이 아닌가 싶군요!

각 시간에서 누가 얼마나 떠드는지가 더 의사 결정에 많은 기여를 했는지 알아보면 재미있을 것 같아서~ 그래프를 뽑아 봤더니 이렇게 나오는군요.

대충, 전체적으로 사람들이 얼마나 얘기하는가를 나타내는 prev, next, curr이 높고, 몇 명 평소에 상당히 규칙적인 생활을 하거나, 말을 많이 하는 분들이 상당히 점수가 높습니다. 시간별로 나눠서 보면, 새벽 0~6시 시간대에는 sakura님과 wooil님의 중요도가 아주 중요한데 패턴을 살펴보면 Sakura님이 말을 많이 하면서도 wooil님이 조용하면 새벽0~6시일 확률이 높다는 것을 알 수 있겠죠. 그리고 오전 9~10시 출근시간 무렵은 cocas님과 mithrandir님의 중요도가 높은데 일찍 일어나서 학교 가기전에 채팅하는 착실한 학생들(?)의 패턴이 아주 주효한 것 같습니다. -ㅇ-; 그리고 대략 저녁 6시 대의 중요도(variable importance)를 보면 퇴근시간이 일정한지 여부를 알 수 있을텐데요, 저녁 6시대에는 거의 높은 사람 없이 골고루 다 낮고, 정확도도 상당히 떨어지는 걸로 봐서는, IRC 사람들은 다들 불규칙한 저녁식사를 하는 모양입니다. -ㅇ-;

그 외의 또 다른 재미있는 지표로, outlier이라고 일반적인 패턴에서 벗어나는 샘플들을 골라내는 방법을 사용해서 상당히 평소와는 다르게 진행된 대화가 있나 한번 살펴보았는데, 3월과 5월에 대해서 outlier 지표를 그려보면 다음과 같이 나옵니다.

피크가 뚝뚝 떨어진 부분이 몇 군데 있는데, 이 부분이 평소와는 상당히 다른 일이 벌어진 경우를 의미합니다. 그래서 그 날짜를 구체적으로 로그를 살펴보면 정말로 평소하고는 아주 다른 일이 발생한 것을 알 수 있는데, 200주변(3월 12일)에는 평소에 밤에는 꼭 주무시는 wooil님이 새벽에 한참 대화를 하시는 이변이 발생한 날이고, 1200주변(5월 20일)에는 평소와는 달리 낮에 3시간동안 아무도 한 마디를 안 한 일이 발생했던 것입니다. 🙂

이제 대충 어느 정도는 정말 누가 말하는 지만 봐도 시간이 감이 오긴 한다는 것이 정량화가 되었는데요, 혹시 대화 패턴과 시간을 알면 요일도 알 수 있지 않을까 생각이 들었습니다. 그러니까.. 평소에는 낮에는 대화 잘 안 하다가 주말만 되면 S모 다방에 가셔서 하루 종일 IRC하시는 jachin님만 보면 일요일인지 당연히 알 수 있다던지 이런 것들도 정보가 되지 않을까 생각했는데, 의외로 통계를 내 보니까 거의 예측을 제대로 못하는게, 역시 IRC사람들은 주말과 평일 구분이 별로 없는 모양입니다;;

이 자료를 토대로 IRC 클라이언트 입력창 옆에 시계를 붙여 볼까 생각을 해 봤지만.. 너무 삽질같아서 포기.;; -ㅇ-;

파이썬3000 국제화 식별자(i18n identifier) 지원 결정

그동안 파이썬에서는 변수 이름, 함수 이름, 클래스 이름 등등에서 영문 알파벳과 숫자, 밑줄만 사용할 수 있었습니다.
전문 개발자들이야 영어가 필수이다보니 그냥 쓰면 된다지만, 어린 애들이나 도구로 프로그래밍을 하는 분들은
영어로 써야한다는 것이 엄청난 어려움으로 다가올 수 밖에 없습니다. 주석을 변수이름에 녹인다는 기법만 적용하려고
해도, 주석은 한글로 쓸 수 있다지만 변수 이름을 한글로 쓰지 못하면 녹여내지 못하고 결국 초딩용 코드 a, b, c가
등장하게 돼서 암호가 돼 버리죠 =.= 그래서 그동안 비영어권 국가 개발자들은 유니코드 식별자의 필요성을
계속 얘기하고 있었고, 한국, 중국, 일본 같은 경우에는 각각 비영어 식별자를 지원하는 패치를 배포하기도 했습니다.

그러던 중, Python3000을 위해 논의되어 왔던 파이썬 비-아스키 식별자 (non-ASCII identifier)가 지난 5월 27일에 드디어 통과되었습니다.
오랫동안 거의 “내 눈에 흙 들어가기 전에는…” 수준으로 비-이스키 식별자 (밑에서는 유니코드ID로 표기)를
싫어하던 귀도가 그동안 내 아들들에게도 자국어로 프로그래밍할 수 있는 기회를 주고 싶다는 마틴, 발터 등의
여러 비영어권 개발자들의 노력으로 설득당해버렸군요. 🙂 (물론 이 뒤에는 무려 메일 1000개가 넘는
여러가지 기술/정책/정치적인 토론이 있었습니다.)
아직 PEP에서는 상세하게 다뤄지지 않았는데, 일단은 PEP번호는
PEP-3131
입니다. (이렇게 내용 없는 PEP가 accept되기는 처음이 아닐까 싶은데, PEP로 정리만
되지 않았지 토론 내용 여기저기에 충분히 의견의 합의는 있었습니다.)

그럼, 한중일에서 그냥 2~3줄 패치해버리는 것으로 간단하게 됐던 한글 허용을 도대체
파이썬에서는 무엇때문에 이렇게 논란이 많은지 고민하실텐데요, 모든 문제의 원천은
소스파일마다 인코딩이 다른 상황 때문에 발생합니다. 소스코드끼리 인코딩이 다를 때
서로를 참조하는 방법을 통일시키려면 시스템 내부의 인코딩을 통일할 수 밖에 없는데,
이것으로 유니코드를 채택하다보니 유니코드에서 발생하는 여러가지 특징들이 문제로 다가오게 됩니다.
한중일의 패치는 그냥 허용 영역만 푼거라서, 사실 이런 것에 대해서는 대책없이 그냥 임시방편으로
풀어놓았던 것이지요.

대표적인 문제를 보자면, 우선 정규화(normalization)문제가 있습니다. 정규화는 똑같은 논리적
글자가 유니코드에서 여러가지 방법으로 표현되기 때문에 발생하는 문제인데, 예를 들어서
한글의 경우에는 “한(U+D55C)”과 같이 완성형으로 표현하는 방법도 있고, “ㅎㅏㄴ(U+1112 U+1161 U+11AB)”같이 조합형으로 풀어서 쓰는 방법이 있습니다. 앞과 같이 최대한 뭉쳐서 표현하는 방식을
NFC(Normalization Form C)라고 부르고, 뒤와 같이 최대한 풀어서 표현하는 방식을
NFD(Normalization Form D)라고 부릅니다. 둘 중 하나로 표현하면 논리적으로 같은 글자가
코드로도 똑같이 표현이 되니까, 코딩 방식을 다르게 했다고 이름이 같은지 모르는 MacOS X 파일시스템같은
상황이 없어집니다. 파이썬에서는 여러모로 내부 목적에 적합하다고 판단하여 NFC로 결정하였습니다.
사실 NFD와 NFC 사이에서는 간단하게 결정되었지만, NFKC와 NFC중에 무엇을 택할지는
좀 애매한 문제여서 토론이 있었는데, 결국은 손실 없이 최대한 줄여 쓰는 NFC를 채택하게 되었습니다.
(NFKC는 손실을 감수하고 줄여씁니다.)

그 외에도 역시 거의 유니코드 글자 속성 전 영역에 대해서 문제가 발생하는데, 이런 것이 있습니다.

  • Breaking: 각 글자가 앞 뒷 단어를 떼어주는 역할을 하는지 속성을 지정합니다. 예를 들어,
    한글{ZWNBS}메롱 이라면 “한글{ZWNBS}메롱” 전체가 한꺼번에 변수 이름이 돼야 하지만,
    한글{ZWBS}메롱 이렇게 썼다면 “한글” “메롱”이 따로 따로 변수 이름으로 인식돼야 합니다.
    (ZWBS=Zero-Width Breaking Space, ZWNBS=Zero-Width Non-Breaking Space)
    그런데, ZWBS같은 경우에는 눈에 안 보이기 때문에, 사람 눈으로 파이썬 소스를 완벽히 분석할
    수 없다는 문제가 발생합니다. 그렇지만, 이런 건 변태들이나 하겠지;; 하고 어쩔 수 없는 문제가
    아닐까 하는군요.
  • 글자 속성: 아스키 문자영역에 대해서는 몇 글자 안 되다보니, 어떤 것이 부호이고, 어떤 것이
    글자인가가 상당히 명확하지만, 유니코드까지 가게 되면 명확하게 숫자, 문자인 것이 있는 반면에
    어떤 것은 숫자인것 같기도 하고 아닌 것 같기도 한 것들이 수도 없이 많습니다. (예를 들어,
    홍콩지역 기수법 문자라던지, 네모 안에 숫자로 들어있는 것 같은 것들은 유니코드 데이터베이스에서는
    여러가지 속성이 같이 기록되어 있지만, 프로그래밍 언어 측면에서는 숫자로 인정해야 할지 변수 이름 글자로
    인정해야 할지 무지 애매하죠.. 10진법을 뛰어 넘는 숫자까지도 존재해서..) 그래서 각 글자 속성에
    대해서 어떤 것을 변수 이름으로 인정하게 하고, 어떤 것을 허용하지 않을지 결정하는 것이 중요한데,
    더욱 애매한 것은 유니코드 버전이 올라가면서 글자가 추가되거나 기존 글자의 속성이 바뀌는 경우도
    있다는 것입니다. -ㅇ-;; (그래서 파이썬에서 지원하는 유니코드 버전이 바뀌면 소스 파싱 방법도 바뀌고..)
  • 왼쪽으로 쓰는 문자체계: 아랍어나 히브리어 같은 경우에 오른쪽에서 왼쪽으로 쓰기 때문에,
    유니코드 처리에서도 상당히 특별하게 처리해 줘야 합니다. 여기서 이제 파이썬 소스코드를 보는 쪽 뿐만
    아니라 소스코드를 출력하는 부분이 있는 traceback이나 IDLE등 수많은 곳에서 오른쪽에서 왼쪽으로
    쓰는 처리를 해 줘야하게 됩니다.

유니코드 쪽의 문제 뿐만 아니라, 파이썬에서 유니코드ID를 디폴트로 허용할 것이냐, 소스쪽에서
옵션으로 풀것이냐, 아니면 파이썬 명령행에서 풀게할 것이냐 등등 디폴트 설정에 관해서 의견이
많이 있었는데, 이건 아직 의견이 팽팽하게 맞서고 있어서 결정되지 않았습니다. 심지어 어떤 사람들은
위에서 언급된 것들 (NFC냐 NFKC냐, 문자 속성 선택 등..)을 런타임에 결정할 수 있게 하자는
사람도 있는데.. 역시 사람들 의견은 정말 다양하군요 -ㅇ-;

그 외에도 여러가지 기술적 문제들이 남아있지만, 결국 정책적으로는 귀도가 파이썬의 내부
파이썬 코딩 스타일 가이드인 PEP-8에서
절대 파이썬 자체 코드 안에서는 ASCII 이외의 문자를 쓰지 말도록 정하였고, 광범위한 개발자들이
참여하는 모든 오픈소스프로젝트에서도 이 규칙을 채택하도록 권고하는 것으로 결정했습니다.

이제 파이썬3000이 나오면 왠지 교육용으로 추천해도 마음에 찔리는 게 없을 것 같아서 무척 좋군요! 🙂