[클린코드] 13장 : 동시성
상 한규
∣
2024년 1월 24일
목록으로 돌아가기
- 동시성이란 - 동시에 실행되는 것처럼 보이는 성질
싱글 코어에서 멀티 스레드를 동작시키는 방식이다.
- 이를 채택하는 이유는 무엇과 언제를 분리하여 어플리케이션 구조와 효율을 극적으로 높이기 위해서다.
- 구조적 관점에서 프로그램이 작은 프로그램들로 쪼개어져 보인다.
- 효율적 관점에서 응답 시간 및 작업 처리량이 개선된다.
- 동시성에 대한 오해
- 동시성은 항상 성능을 높여준다.
→ 여러 스레드 및 프로세서가 동시에 처리할 독립적인 계산이 충분히 많다는 조건이 붙는다.
- 동시성을 구현하면 설계는 변하지 않는다.
→ 단일 스레드와 다중 스레드 시스템은 설계가 아예 다르다.
- 웹 또는 EJB 컨테이너를 사용면 동시성을 이해할 필요가 없다.
→ 컨테이너의 동작을 봐야하며 동시 수정 및 데드락과 같은 문제의 해결책을 알아야한다.
- 동시성에 대한 타당한 이야기
- 동시성은 다소 부하를 유발한다.
→ 성능에 부하를 유발하며, 코드도 길어진다.
- 복잡하다.
- 동시성 버그를 재현하기 어렵다.
→ 결함으로 간주되기 어려우며 일회성 문제로 여겨질 가능성이 농후하다.
- 근본적인 설계 전략을 재고해야한다.
- 동시성 방어 원칙
- 단일 책임 원칙
- 동시성 관련 코드는 다른 코드와 분리해야한다.
- 따름 정리: 자료 범위를 제한하라→ 캡슐화
- 공유 객체를 사용하는 코드 안에 임계 영역을 synchronized 키워드로 보호해야한다.
- 이러한 임계영역은 최대한 줄여야한다. 그렇지 않으면, 보호할 임계영역을 빼먹거나, 이를 확인할 때 수고를 더 들이게 된다.
- 따름 정리: 자료 사본을 사용하라
- 따름 정리: 스레드는 가급적 독립적으로 구현하라
- 다른 스레드와 자료를 공유하지 말자.
- 각 스레드는 클라이언트 요청 하나만 처리한다.
- 모든 정보는 비공유 출처에서 가져오며, 로컬 변수에 저장한다.
- 라이브러리를 이해하라
- 라이브러리를 이해하여 스레드 환경에 안전한 컬렉션을 사용하자.
자바) java.util.concurrent패키지가 제공하는 클래스는 다중 스레드 환경에서도 안전하며 성능이 좋다.
- 실행 모델을 이해하라
- 한정된 자원, 상호 배제, 기아, 데드락, 라이브락 등
- 생산자 - 소비자 관계
- 생산자 스레드 → 정보 생성 후 버퍼나 대기열에 입력
- 소비자 스레드 → 정보 소비
- 스레드가 사용하는 대기열은 한정된 자원
- 무한 대기를 유의해야함
- 읽기 - 쓰기 관계
- 읽기 스레드 - 공유 자원 사용
- 쓰기 스레드 - 공유 자원 갱신
- 균형을 통해 처리율 향상 및 기아 방지 유의
- 식사하는 철학자들
- 기업 어플리케이션은 여러 프로세스가 자원을 얻으려고 경쟁함
- 데드락, 라이브락 등 효율성 저하 상황을 유의해서 설계해야함.
- 동기화하는 메서드 사이에 존재하는 의존성을 이해해라
- 위의 사이에 의존성이 존재하면 동시성 코드에 어려운 버그가 생긴다.
- 위의 메서드가 여럿이라면 구현이 올바른지 확인해야한다.
- 공유 객체 하나에 여러 메서드가 불가피하다면 클라이언트에서 메서드 호출 직전 서버를 잠그고, 메서드 호출 후 잠금을 해제해야한다.
- 동기화하는 부분을 작게 만들어라
- 올바른 종료 코드는 구현이 어렵다.
- 깔끔하게 종료하는 다중 스레드를 짜야한다면 시간을 투자해 올바르게 구현하자. 특히 데드락을 조심하자.
- 초기부터 많은 시간을 투자하고, 이미 나온 알고리즘을 검토하자.
- 스레드 코드 테스트
- 단일 스레드의 경우 충분한 테스트는 완벽하게 안전하진 않지만, 위험을 낮춘다.
- 설정과 부하를 자주 바꿔가며 테스트하자.
- 테스트가 실패한다면 반드시 원인을 추적하자. 그냥 넘겨선 안된다.
- 말도 안되는 실패는 잠정적으로 스레드 문제로 취급하라.
- 일회성 문제란 존재하지 않는 가정이 안전하다. 이를 무시한다면, 잘못된 코드 위에 코드가 계속 쌓이게 된다.
- 다중 스레드를 고려하지 않은 순차 코드부터 제대로 돌게 만들자.
- 스레드 환경 밖에서 코드가 제대로 도는지 반드시 확인하자.
- POJO를 사용하자.
- 다중 스레드를 쓰는 코드 부분을 다양한 환경에 쉽게 끼워 넣을 수 있게 코드를 구현하라.
- 실행 스레드 수를 바꾸거나, 다양한 환경, 속도 등을 반복적으로 테스트하자.
- 다중 스레드를 쓰는 코드 부분을 상황에 맞게 조율할 수 있게 작성하라
- 적절한 스레드 개수를 판단하려면 많은 시행착오가 필요하므로, 이를 쉽게 조율 할 수 있는 코드를 구현하자.
- 프로세서 수보다 많은 스레드를 돌려보라
- 임의로 스와핑을 일으켜 임계영역을 빼먹은 코드나 데드락을 일으키는 코드를 파악하여 수정하자.
- 다른 플랫폼에서 돌려보라
- 다중 스레드 코드는 플랫폼에 따라 다르게 동작하므로, 여러 플랫폼에서 테스트해보자.
- 코드에 보조 코드를 넣어 돌려라. 강제로 실패를 일으키라.
- 보조 코드를 추가하여 코드 실행 순서를 바꿔준다. 이를 통해 오류를 더 자주 일으키게 해준다.
- 이의 방법은 두가지다
- 직접 구현
- 자동화 : AOP, CGLib, ASM 등 사용
댓글