The Zen of Parallel Programming

Hacker News · 2026.07.26
The Zen of Parallel Programming

병렬 프로그래밍이 가르쳐 주는 것

병렬 프로그래밍을 공부하다 보면 흥미로운 사실을 하나 깨닫게 된다. 인간 유전체 해독, 의료 영상 처리, 기후 모델링, 단백질 구조 예측 등 현대 컴퓨팅의 거대한 성취들은 모두 병렬 처리 덕분에 가능해졌다. 그런데 그 핵심 교훈은 "더 많은 프로세서를 추가하면 자동으로 더 많은 유용한 작업이 이뤄진다"가 아니다. 프로세서를 아무리 늘려도, 조율 없이는 성능이 오히려 저하된다.

병렬 시스템이 제대로 작동하려면 세 가지가 필요하다. 문제를 나누고(decomposition), 나뉜 부분이 서로 소통하며(communication), 작업 부하를 균형 있게 분산(load balancing)해야 한다. 특정 프로세서 하나만 과부하 상태인데 나머지가 대기한다면, 그 시스템은 전체 성능을 낭비하고 있는 것이다.

백엔드 시스템에서 마주치는 똑같은 문제

Java 백엔드 개발에서도 이 구조는 그대로 반복된다. 멀티스레드 환경에서 모든 스레드가 같은 락 하나를 두고 경쟁한다면, 프로세서를 늘려도 처리량은 오히려 떨어진다. synchronized 블록을 무분별하게 사용하거나, 공유 자원에 대한 접근을 세밀하게 설계하지 않으면 병렬성의 이점은 사라진다.

// 나쁜 예: 메서드 전체를 동기화해 병목 생성
public synchronized void processOrder(Order order) {
    validate(order);       // 공유 자원 불필요
    persist(order);        // 공유 자원 필요
    notifyUser(order);     // 공유 자원 불필요
}

// 개선: 꼭 필요한 영역만 동기화
public void processOrder(Order order) {
    validate(order);
    synchronized (this) { persist(order); }
    notifyUser(order);
}

비동기 처리도 마찬가지다. CompletableFuture나 리액티브 스트림을 도입하는 것 자체가 목적이 아니라, 어디서 병목이 생기는지, 어떤 작업이 독립적으로 실행 가능한지를 먼저 파악하는 것이 핵심이다. 설계 없이 스레드 풀 크기만 늘리는 것은 프로세서를 추가하는 것과 같은 함정이다.

조율이 성능을 결정한다

병렬 프로그래밍에서 가장 어려운 문제는 결국 동기화(synchronization)와 소통(communication) 이다. 한 프로세서가 다른 프로세서의 결과를 기다려야 할 때, 그 대기 시간이 전체 성능의 상한선이 된다. Amdahl의 법칙이 말하는 것도 이것이다. 병렬화할 수 없는 직렬 구간이 전체 성능을 지배한다.

실무에서 이는 서비스 간 통신 설계로 이어진다. 마이크로서비스 아키텍처에서 API 하나가 다른 서비스 세 개를 순차 호출한다면, 가장 느린 서비스가 전체 응답 시간을 결정한다. 독립적인 호출은 병렬로 묶고, 결과를 취합하는 지점을 명확히 설계하는 것이 곧 병렬 프로그래밍의 철학을 시스템 설계에 적용하는 것이다.

CompletableFuture<User> userFuture = CompletableFuture.supplyAsync(() -> userService.find(id));
CompletableFuture<List<Order>> orderFuture = CompletableFuture.supplyAsync(() -> orderService.findByUser(id));

CompletableFuture.allOf(userFuture, orderFuture).join();
// 두 호출이 독립적이므로 병렬 실행 가능

정리

  • 프로세서(스레드)를 추가하는 것보다 분해, 소통, 부하 균형 설계가 먼저다
  • 동기화 범위를 최소화하고, 독립적인 작업은 병렬로 묶어야 실질적인 성능 향상이 가능하다
  • Amdahl의 법칙을 기억하라. 직렬 구간이 병렬화의 천장을 결정한다
Source
Hacker News
원문 보기 →
← 목록으로 돌아가기