Programming Erlang 을 읽다 든 생각

얼마 전에 Pragmatic Version Conrol using Git 이랑 같이 구입한 Programming Erlang을 읽는 중이다. 읽다가 드는 생각은, 멀티스레드 프로그래밍 혹은 병행 프로그래밍(concurrent programming)은 그 “원칙"에서 거기서 거기구나란 느낌이 든다.

Erlang에서 병행 프로그래밍이 쉽고/성능이 잘 나온다는 이유로 강조하는게,

  • 변수 대입에 부가 효과(side-effect)가 없다 (erlang에선 변수에 한 번 대입하고 나면 끝이다)
  • 스레드/프로세스 간 동기화는 메시지 패싱을 통해서만 이루어진다
  • 스레드간 통신은 비동기적이다
  • 분산 환경(RPC-like distributed env.) 구축이 쉽다
  • side-effect가 없는1 함수형 언어

정도였다.

실제로 C/C++로 병행 서버를 작성할 때에 보통 하는 일들이,

  • 메시지 패싱등을 사용하는 비동기 (작업) 큐 구현
  • 메시지 패싱을 통한 느슨한 동기화
  • 모든 작업은 비동기 적이며, continuation 같은 구현(혹은 closure나 C++ 0x lambda 같은 류)이 흔하다
  • 상수 값 사용이 많다. 변수들은 흔히 상수부(한 번 초기화 되고 변경하지 않는)와 변경 가능한 부분을 분리하고, 변경 가능한 부분에 적당한 동기화를 수행하게 짠다. 락을 쓰든  RCU를 쓰든, 동기화 큐를 만들든 …

이런 일이다. 덤으로 부가 효과라는게 생각만큼 — 그러니까 싱글스레드만큼 — 쉽게 쓸 수 있는게 아니게 되어서, 가능하면 함수형 언어에 가깝게 만든다. 힙 대신에 스레드 로컬한 장소 — 스택이라거나 TLS라거나 — 에 값을 보관한다거나. 비동기적으로 실행되고 / 중단되고 / 재개되는 closure 비슷한 것들(co-routine이라거나 C++ 0x lambda + thread 라거나, MS Windows fiber 류의 유저 레벨 스레드 팩키지 라거나 )을 사용한다.

다만 erlang에서 맘에 들었던 점은 — erlang이 만들어진 목적 때문이겠지만 — 이런 메시지 패싱 자체가 언어 자체 프레임웍으로 구현되어 있다는 것. 그리고 C/C++ 환경에서 프로그래머가 신경써야하는 상수 값 (혹은 단일 초기화 원칙) 을 언어 런타임이 처리한다는 것은 훌륭하다. 다만 게임 서버 같이 꽤나 단단히 묶여있는(tightly coupled system) 류의 응용에서 흔히 나오는 여러 값의 동시 업데이트 — 약간은 트랜잭션 같은 류의 — 는 어찌 처리해야할지는 아직 감이 잘 안온다.

ps. Project Euler를  erlang 연습삼아 풀어보고 있는데, 언어 자체의 라이브러리 탓인듯도 하지만 문자열 다루는게 너무 귀찮게 되어있어서 괴롭다. Python도 값이 상수라는 건 똑같(?)지만 이렇게 힘들진 않았는데(사실 그건 파이썬이 여러번 대입할 수 있어서 일지도 모르지만), 스크립트 언어류를 쓰다가 좀 더 static한 언어를 쓰려니 귀찮다.


  1. 사실 전역 테이블을 다루는 API가 있어서 완전히 그런건 아니지만 그런 연산은 사실상 지양되는 걸로 보이니 그건 빼고 생각하겠다. ↩︎