클린코드 13 - 동시성

yesjm·2024년 5월 10일
0

클린코드를 읽자

목록 보기
13/13

객체는 처리의 추상화다. 스레드는 일정의 추상화다.

동시성과 깔끔한 코드는 양립하기 아주 어렵다

동시성이 필요한 이유

  • 동시성은 결합(Coupling)을 없애는 전략이다.
  • 무엇과 언제를 분리하는 전략이다.
  • 응답 시간과 처리량 개선
  • 많은 사용자를 동시에 처리하면 시스템 응답 시간을 높일 수 있다.
  • 대량의 정보 병렬 처리

동시성 방어 원칙

단일 책임 원칙 Single Responsibility Principle, SRP

  • SRP는 주어진 메서드/클래스/컴포넌트를 변경할 이유가 하나여야 한다는 원칙이다.
  • 동시성은 복잡성 하나만으로도 따로 분리할 이유가 충분하다. 즉, 동시성 관련 코드는 다른 코드와 분리해야 한다.

자료 범위를 제한하라

  • 객체 하나를 공유한 후 동일 필드를 수정하던 두 스레드가 서로 간섭하므로 예상치 못한 결과를 내놓는다.
  • 공유 객체를 사용하는 코드 내 임계영역을 synchronized 키워드로 보호하라고 권장한다.
  • 자료를 캡슐화 하고 공유 자료를 최대한 줄여라

자료 사본을 사용하라

  • 공유 자료를 줄이려면 처음부터 공유하지 않는 방법이 제일 좋다.
  • 어떤 경우에는 객체를 복사해 읽기 전용으로 사용하는 방법이 가능하다.
  • 어떤 경우에는 각 스레드가 객체를 복사해 사용한 후 한 스레드가 해당 사본에서 결과를 가져오는 방법도 가능하다.

스레드는 가능한 독립적으로 구현하라

  • 다른 스레드와 자료를 공유하지 않는다.
  • 각 스레드는 클라이언트 요청 하나를 처리한다.
  • 모든 정보는 비공유 출처에서 가져오며 로컬 변수에 저장한다.
  • 독자적인 스레드로, 가능하면 다른 프로세서에서, 돌려도 괜찮도록 자료를 독립적인 단위로 분할하라.

라이브러리를 이해하라

  • 언어가 제공하는 클래스를 검토하라.

실행 모델을 이해하라

생산자-소비자 Producer-Consumer
읽기-쓰기 Readers-Writers
식사하는 철학자들 Dining Philosophers

동기화하는 메서드 사이에 존재하는 의존성을 이해하라

  • 동기화하는 메서드 사이에 의존성이 존재하면 동시성 코드에 찾아내기 어려운 버그가 생긴다.
  • 공유 클래스 하나에 동기화된 메서드가 여럿이라면 구현이 올바른지 확인하자
  • 공유 객체 하나에는 메서드 하나만 사용하라
  • 공유 객체 하나에 여러 메서드가 필요한 상황인 경우
    - 클라이언트에서 잠금: 클라이언트에서 첫 번째 메서드를 호출하기 전에 서버를 잠근다. 마지막 메서드를 호출할 때까지 잠금을 유지한다.
    • 서버에서 잠금: 서버에다 "서버를 잠그고 모든 메서드를 호출한 후 잠금을 해제하는" 메서드를 구현한다. 클라이언트에서 호출
    • 연결 서버: 잠금을 수행하는 중간 단계를 생성한다. '서버에서 잠금' 방식과 유사하지만 원래 서버는 변경하지 않는다.

동기화하는 부분을 작게 만들어라

  • 여기저기서 synchronized 문을 남발하는 코드는 바람직하지 않다.
  • 반면, 임계영역은 반드시 보호해야 한다. 임계영역 수를 최대한 줄이자.
  • 필요 이상으로 임계영역 크기를 키우면 스레드 간에 경쟁이 늘어나고 프로그램 성능이 떨어진다.

올바른 종료 코드는 구현하기 어렵다

  • 영구적으로 돌아가는 시스템을 구현하는 방법과 잠시 돌다 깔끔하게 종료하는 시스템을 구현하는 방법은 다르다.
  • 깔끔하게 종료하는 코드는 올바로 구현하기 어렵다.
    가장 흔히 발생하는 문제 데드락
  • 생각보다 어려우므로 이미 나온 알고리즘을 검토하자

스레드 코드 테스트하기

  • 코드가 올바르다고 증명하기는 현실적으로 불가능하다. 테스트가 정확성을 보장하지는 않지만 충분한 테스트는 위험을 낮춘다.
  • 말이 안 되는 실패는 잠정적인 스레드 문제로 취급하라.
    '일회성'이라 치부하지 마라
  • 다중 스레드를 고려하지 않은 순차 코드부터 제대로 돌게 만들자.
  • 다중 스레드를 쓰는 코드 부분을 다양한 설정으로 실행하기 쉽게 구현하라
  • 다중 스레드를 쓰는 코드 부분을 상황에 맞게 조율할 수 있게 작성하라
  • 프로세서 수보다 많은 스레드를 돌려보라
    스와핑이 잦을수록 임계영역을 빼먹은 코드나 데드락을 일으키는 코드를 찾기 쉬워진다
  • 다른 플랫폼에서 돌려보라
  • 코드에 보조 코드instrument를 넣어 돌려라. 강제로 실패를 일으키게 해보라
  • 자동화
    보조 코드를 자동으로 추가하는 도구를 사용한다.
    흔들기 기법을 사용해 오류를 찾아내자

결론

다중 스레드 코드는 올바로 구현하기 어렵다.
각별히 깨끗하게 코드를 짜야 한다.

profile
yesjm's second brain

0개의 댓글