'Erlang'에 해당되는 글 1건

  1. 2011/11/08 Erlang으로 팩토리얼 계산해보기 (1)

최근 정말 우연히 Programming Erlang(조 암스트롱, 인사이트)이라는 책을 접했는데, 함수형 언어이고 분산 처리에 적합하게 설계되며 실제로 많이 쓰이고 있다는(!) 것에 감명을 받아 열심히 공부하고 있다. 아직 다 읽지는 못했지만 공부 한 내용을 블로그에 정리해 두려고 한다. (아직 공부한 지 일주일도 되지 않아 코드가 세련되지 못할 수도 있으니 코멘트 부탁드립니다.)

얼랭을 처음 보았을 때의 느낌은 함수형 언어라는 면에서는 LISP와 굉장히 닮았고(실제로 LISP의 많은 철학과 용어를 차용한 것 같다) 문법은 Scala와 많이 유사하다는 것이었다. 일반적으로 C나 Java와 같은 언어로 프로그래밍을 시작한 사람들에게 있어 가장 혼란스러운 부분은

  • 변수가 없다.
  • 반복문이 없다.
일 것이다. 저장해야 할 자료는 모두 함수의 매개변수에 담아 놓고, 반복문을 작성하는 대신 함수를 재귀호출해야 한다는 함수형 언어의 특징이 낯설 수도 있었을텐데, 다행히 나는 Scheme에 조금은 익숙한 상태라 큰 반감 없이 받아들일 수 있었다.

그럼 본론으로 넘어가서 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 좋구나.

이올린에 북마크하기