멀티코어 활용할 방법이 정말 멀티스레딩 뿐이라고?

예전에 ‘Multicore의 concurrency를 위해선 멀티스레딩 뿐인가?" 라는 글을 썼다.

OpenMP나 tbb, 혹은 MS의 Parallel Patterns Library 모두 일을 더 쉽게 만들어주는게 아니다. 그네들은 병렬 프로그래밍을 쉽게해주는 기능을 제공해 주긴 한다. 하지만 당연히 싱글스레드 프로그래밍보다 어렵다. 즉, 원래 목표여야 하는 “병렬 하드웨어 활용을 쉽게해주는 것” 이 아니다. 이 툴들의 목적은 현재 단일 스레드로 작성한 프로그램을 , 어떻게 멀티스레드 프로그램으로 수정하면 병렬 하드웨어를 좀 더 잘 쓸 수 있을까 하는 경우를 해결하는 것이다. 이거랑 멀티코어 CPU를 잘 쓰는 일은 동일한게 아니다.

쉬운 길은 이미 “많은 프로그램들이 잘 하고 있는 일"이다.간단하게, 하드웨어가 병렬화가 되면 ‘할 일을 더 주면 된다’. (Gustafson’s Law) 웹 서버나, hadoop처럼 부하가 늘어나면 작업 단위를 처리하는 ‘프로세스를 더 많이 띄우면 된다’.복수의 프로세스(스레드)가 특정 상태를 공유하면서 / 업데이트하지 않는 이상, 이 방법은

  • 작성하기 익숙하고 (익숙한 싱글스레드 프로그램이다!)
  • 디버깅 하기 쉽고 (멀티스레드 프로그램은 비결정론적이다)
  • 기존 코드를 거의 변경하지 않아도 된다

라는 엄청난 장점이 있다.

서버 프로그래밍의 — 특히 게임 서버 프로그래밍 — 목적은, 지연 시간을 일정 이하로 유지하는 수준에서 최대 처리량(throughput)을 얻는 것에 있다고 생각한다. 즉, 개별 서버 프로세스가 비슷한 일 — 프로세스마다 1개 채널의 로비를 처리한다거나 — 을 처리해서 부하를 적당히 쪼개고, 싱글스레드에서 처리가능한 수준1 의 부하를 담당한다면, 굳이 이걸 omp/tbb/ppl 같은 걸 써서 복잡하게 짤 이유는 없지 않은가?

물론 공유 상태가 많으면 MT로 짤 수는 있겠지만, 그 경우에도 비슷한 원칙을 유지한다.

  • 싱글스레드화 되는 부분 — 동기화 처리부분 — 은 메시지 교환 등으로 우회하거나, 최소화하고
  • 같은 일을 하는 프로세스 대신 스레드를 여럿 둔다
  • 그리고 이 스레드의 수만 늘린다

즉, 본질적으로는 일부분을 제외하고는 싱글스레드 프로그래밍을 하고, 이 부분을 늘려서 주어진 병렬 하드웨어를 잘 쓰자라는 것.

그러니까, 싱글 스레드 성능 향상이 목적이 아니라면, omp/ppl/tbb 다 그렇게 영양가 높은 얘기는 아니다라는게 내 생각이다.2 오히려, 전체 구조를 잘 생각하고 똑같은게 여러 개 돌 부분을 찾고, 이 부분을 여럿 띄울 생각을 하는게 — 예를 들자면 마비노기 영웅전의 micro-kernel 틱한 구조에서 개별 서비스를 여러 개 띄우는 것 처럼 — 생산적인게 아닐까?

그 이전에(…) 서버 자체는 많은 경우 애초부터 멀티스레드로 짜고, 독립적으로 할 수 있는 부분도 많기 때문에 tbb같은게 적합할 태스크 패러럴, 혹은 데이터 패러럴한 워크로드가 아닌 것도 좀… 코어를 다 차지할 만큼의 스레드들이 있는데, 굳이 단일 스레드 프로그래밍에서 CPU  코어 여러개 쓰기 위한 방법을 가져다 쓸 이유가 있을까?

내가 리뷰 안 쓰는 무언가 때문에 이런 글을 썼다고 느끼면 “그게 다 기분 탓” 입니다.


  1. 지연 시간이 폭증하지 않는 한. ↩︎

  2. 물론 일부분, 예를 들어 tbb scalable allocator라거나 concurrent container류는 그 자체만으로 쓸모있는 라이브러리이기 때문에 여기저기 쓸 곳이 많다. 그렇지만 parallel_for, parallel_reduce 함수가 모든 상황에서 유용한가? ↩︎