최근 정말 우연히 Programming Erlang(조 암스트롱, 인사이트)이라는 책을 접했는데, 함수형 언어이고 분산 처리에 적합하게 설계되며 실제로 많이 쓰이고 있다는(!) 것에 감명을 받아 열심히 공부하고 있다. 아직 다 읽지는 못했지만 공부 한 내용을 블로그에 정리해 두려고 한다. (아직 공부한 지 일주일도 되지 않아 코드가 세련되지 못할 수도 있으니 코멘트 부탁드립니다.)
얼랭을 처음 보았을 때의 느낌은 함수형 언어라는 면에서는 LISP와 굉장히 닮았고(실제로 LISP의 많은 철학과 용어를 차용한 것 같다) 문법은 Scala와 많이 유사하다는 것이었다. 일반적으로 C나 Java와 같은 언어로 프로그래밍을 시작한 사람들에게 있어 가장 혼란스러운 부분은
- 변수가 없다.
- 반복문이 없다.
그럼 본론으로 넘어가서 Erlang으로 Factorial을 계산하는 코드를 작성해 보고 실행 시간을 비교해 보고자 한다. 우선, 가장 쉽게 생각할 수 있는 코드는 다음과 같을 것이다. 좋은 코드이지만, Erlang의 장점인 병렬 처리를 충분히 활용하지 못한 코드인 것 같다. 이번에는 병렬 처리를 위해 다음과 같은 코드를 생각할 수 있다. 이 코드는 크게 네 부분으로 구성된다. 우선 fact/1은 작은 문제의 답을 모으는 collector를 띄운 후 문제를 작은 문제로 분할한다. 이 때 작은 문제의 크기는 T의 값에 의해 결정된다. 우선은 T=10000이라는 상수로 두었다. split/4는 문제를 작은 문제들로 분할하는 함수이다. 큰 문제를 T 이하의 크기의 작은 문제 하나와 나머지 크기의 문제로 나눈 후 각각을 푸는 방식이다. 일종의 Divide & Conquer라고 생각할 수도 있겠다. fact/2, fact/3은 먼저 살펴 본 코드와 크게 다르지 않고, 다만 값을 반환하는 것이 아니라 C로 보낸다는 것이 다르다. 마지막으로 collector/3은 작은 문제의 개수를 기억하고 있어서 그 개수 만큼의 답을 얻으면 얻은 답의 곱을 fact/1로 보낸다.
가령 50000!을 계산하고자 한다면, 이 코드는 10000! * (10001 * ... * 20000) * ... * (40001 * ... * 50000)을 계산할 것이다. 싱글 코어라면 오히려 문제를 분할하고 합치는 데에 overhead가 발생하여 성능 저하가 일어나겠지만, 멀티 코어 시스템에서는 작은 문제를 각 코어에서 처리할 수 있으니 더 빠른 성능을 보여 줄 것이라 기대할 수 있다.
실제로, 성능 분석을 해 보면 50000!을 계산하는 데에 처음 제시한 코드는 3095ms, 병렬 처리를 사용한 두 번째 코드는 1059ms가 소요되었다.(i3 머신에서 statistics/1 사용하여 5회 테스트 한 평균) 대략 3배 정도 빠르다는 것을 알 수 있다!
심심하여 큰 수를 자유롭게 계산할 수 있는 또 하나의 언어인 Python으로도 팩토리얼을 구하는 함수를 작성한 후 분석을 해 보았다. 같은 조건에서 5회 테스트 평균을 구해 보았더니 5999ms가 나왔다. 이것은 병렬 처리를 사용하지 않은 Erlang 버전의 2배, 병렬 처리를 사용한 Erlang 버전의 6배 수준이다. 아, Erlang 좋구나.
퍼가고자 하시는 분은 링크를 달아 주시기 바랍니다.




댓글을 달아 주세요
좋구나.