티스토리 뷰
동시성이 필요한 이유?
동시성은 결합을 없애는 전략이다. 무엇(what)과 언제(when)을 분리하는 전략이다.
무엇(what)과 언제(when)을 분리하면 애플리케이션 구조와 효율이 극적으로 나아진다.
하나의 구조 내에 더 작은 구조들로 문제를 분리하여 시스템의 이해를 도울 수 있다.
이런 구조적인 개선뿐만 아니라 동시성은 다양한 작업을 동시에 처리함으로써 작업시간 면에서도 상당한 성능 향상을 가져다줄 수 있다.
미신과 오해
동시성은 항상 성능 향상을 가져다 준다.
여러 프로세서가 독립적으로 처리할 계산이 많은 경우에 성능이 높아지지만 안 그런 경우도 많다.
동시성을 구현해도 설계는 변하지 않는다.
단일 스레드 시스템과 다중 스레드 시스템은 다른 아키텍처를 가지고 있다. 동시성 여부에 따라서 시스템의 설계가 바뀐다.
웹 또는 EJB 컨테이너를 사용하면 동시성을 이해할 필요가 없다.
실제로 어떻게 동작하는지, 그리고 동시성으로 인해 발생할 수 있는 여러 오류 (동시 수정, 데드락)를 피할 수 있는 방법을 알기 위해서 동시성에 대한 이해는 필요하다.
동시성 방어 원칙
동시성으로 인해 발생하는 문제를 방어하는 기술은 다음과 같다.
단일 책임 원칙(Single Responsibility Principle, SRP)
주어진 메서드/클래스를 수정할 이유는 각각 한 가지 씩만 가져야 한다. 동시성을 가진 코드는 동시성 해결을 위해 따로 분리해야 한다.
따름 정리(corollary): 자료 범위를 제한하라
객체 하나에 대해서 다른 스레드가 동시에 동일 필드를 수정하게 되면 오류가 발생할 수 있다.
이런 문제를 해결하기 위해 코드 내 임계 영역을 synchronized 키워드로 보호하는 것을 권장한다.
이렇게 임계영역 수를 줄이는 것이 좋다. 공유 가능성이 있는 영역이 많아질수록 에러를 찾는 노력, 임계 영역에 대한 관리를 하는 시간이 늘어나서 비효율적이다.
따름 정리: 자료 사본을 사용하라
접근 가능한 자료에 대해서 자료 원본을 수정하지 말고, 객체를 복사해 읽기 전용으로 사용할 수 있다. 스레드를 복사해서 사용하고, 그 사본에 대한 결과를 사용하는 방법도 가능하다.
따름 정리: 스레드는 가능한 독립적으로 구현하라
가능한 스레드를 독립적으로 구현하여 다른 스레드와의 자료 공유를 사전에 예방한다. 각 스레드는 클라이언트의 요청을 하나씩 처리하는데, 필요한 정보는 비공유 출처에서 가져와 로컬 변수에 저장한다.
그래서 각 스레드는 자신 이외에 다른 스레드와 접촉할 일이 없다.
실행 모델을 이해하라
한정된 자원 (bound resource) : 다중 스레드 환경에서 사용하는 자원으로, 크기나 숫자가 제한적이다.
상호 배제 (Mutual Exclusion) : 한 번에 한 스레드만 공유 자원을 사용할 수 있는 경우를 말한다.
기아(Starvation) : 한 스레드나 여러 스레드가 자원을 계속 기다리는 상태. 한 스레드가 자원을 계속해서 사용하게 되면 다른 스레드는 기아 상태에 빠지게 된다.
데드락(Deadlock) : 모든 스레드가 다른 스레드가 필요한 자원을 가지고 있는 상태이기 때문에 어떤 스레드도 더 이상 작업을 진행하지 못하는 상태
라이브락(Livelock) : 락을 거는 단계에서 각 스레드가 서로를 방해한다. 스레드는 계속해서 진행하려 하지만 공명(resonance)으로 인해 오랫동안 진행하지 못하는 상태.
생산자-소비자
생산자 스레드는 정보를 생성해 버퍼나 대기열에 정보를 저장하고, 소비자 스레드는 버퍼나 대기열에서 정보를 가져와서 사용한다. 생산자 스레드는 여유 공간이 있어에 정보를 저장 가능하고, 소비자 스레드는 정보가 담겨있어야 정보를 가져와서 사용할 수 있습니다. 생산자 스레드와 소비자 스레드는 저장 공간에 대한 정보를 시그널로 전달받으며 내부의 정보를 사용하는데 이때 양쪽 스레드 둘 다 진행 가능함에도 동시에 시그널을 기다릴 가능성을 생각하고 있어야 한다.
읽기-쓰기
쓰기 스레드가 자원을 갱신하는 동안 읽기 스레드가 자원을 사용할 수 없게 되는 경우 문제가 된다. 그래서 쓰기, 읽기 처리율을 적절히 조절하여 어떤 스레드도 기아 상태에 빠지지 않게 방지하는 방법이 필요하다.
식사하는 철학자들
공유 자원을 사용함에 있어서 어떤 문제가 발생하는지 알려주는 유명한 케이스이다.
서로 다른 스레드가 필요한 자원을 공유하게 되면 데드락, 라이브락, 처리율 저하, 효율성 저하 등을 초래할 수 있다.
동기화하는 메서드 사이에 존재하는 의존성을 이해하라
동기화하는 메서드 사이에 의존성이 존재하면 동시성 코드에 찾기 어려운 버그가 생긴다. 공유 객체 하나에 메서드 하나만 사용하도록 한다.
동기화하는 부분을 작게 만들어라
자바에서 synchronized 키워드를 사용하면 다른 스레드에서 사용하지 못하도록 락을 걸게 된다. 같은 락으로 감싼 부분은 한 번에 한 스레드만 실행 가능하다. 그래서 락은 스레드를 지연시키고 부하를 가중시키기 때문에 크기를 최대한 작게 해야 한다. 락 영역의 개수와 크기를 적절하게 작게 유지하는 것이 중요하다.
올바른 종료 코드는 구현하기 어렵다
완벽하게 종료되는 코드는 데드락의 위험성이 크기 때문에 구현하기 어렵다.
부모 스레드에서 자식 스레드로 종료 시그널을 보내면서 자식 스레드로 시그널이 제대로 전달되지 않을 경우 이후 부모 스레드는 자식 스레드의 응답을 계속해서 기다리게 된다.
종료 코드를 곧바로 작성하는 것을 어렵기 때문에 기존에 존재하는 로직을 참고하는 것을 추천하고 있다.
스레드 코드 테스트하기
코드가 완벽하게 증명하기는 현실적으로 불가능하지만, 충분한 테스트는 위험성을 낮추어준다. 스레드가 두 개 이상 되면 시스템이 복잡해지기 때문에 다음과 같은 지침들을 따르는 것을 권장하고 있다.
말이 안 되는 실패는 잠정적인 스레드 문제로 취급해라
다중 스레드 코드는 말이 안되는 오류를 발생할 때가 있다고 한다. 이때 아주 가끔씩 발생하는 오류라도 일시적인 오류로 판단할 것이 아니라 현재 로직이 가지고 있는 잠재적인 오류로 인지하고 있는 것이 좋다.
다중 스레드를 고려하지 않은 순차 코드부터 제대로 돌게 만들자
스레드 내부와 외부의 에러를 분명하게 구분하여 디버깅하기 위해 먼저 스레드 외부의 로직이 제대로 동작하는지 확인한다.
다중 스레드를 쓰는 코드 부분을 다양한 환경에 쉽게 끼워 넣을 수 있게 스레드 코드를 구현하라
- 스레드를 여러 개 사용하거나, 하나를 사용하거나, 실행 중간에 스레드가 바뀌는 경우
- 스레드 코드를 실제 환경에서 실행한 경우, 테스트 환경에서 실행한 경우
- 테스트 코드를 다양한 속도로 테스트한다
- 반복이 가능한 테스트 코드를 작성한다.
다양한 환경에서 실행할 목적으로 이식성이 높은 코드를 작성할 수 있도록 한다.
다중 스레드를 쓰는 코드 부분을 상황에 맞게 조율할 수 있게 작성하라
시스템에 적절한 스레드를 찾는 과정은 시행착오를 많이 겪어야 한다.
시스템에 따라 스레드를 조율할 수 있도록 코드를 작성하는 것이 중요하다.
프로세서 수보다 많은 스레드를 돌려보라
시스템이 스레드를 스와핑 하기 위해서는 스레드 수가 프로세스 수보다 많아야 한다.
다른 플랫폼에서 실행하라
다중 스레드 코드는 플랫폼에 따라 다르게 동작하기 때문에 최대한 많이, 자주, 다양한 플랫폼에서 테스트해보는 것이 좋다.
강제로 실패를 발생시켜라
스레드 코드에 대한 오류가 자주 발생하진 않기 때문에, 테스트 과정에서 스레드간 순서를 바꿔가면서 일부러 오류 상황을 만들어내 그 오류를 수정하면 더 견고한 코드가 될 것이다.
'Books' 카테고리의 다른 글
[GraphQL] 2장 그래프 이론 (0) | 2022.06.04 |
---|---|
[GraphQL] 1장 GraphQL이란 (0) | 2022.06.02 |
[Clean Code ] #12 창발성 (0) | 2022.05.10 |
[Clean Code] #11 시스템 (0) | 2022.05.10 |
[Clean Code] #10 클래스 (0) | 2022.05.09 |
- Total
- Today
- Yesterday
- 문제풀이
- python
- v-for
- redux-thunk
- webpack
- React
- TypeScript
- Vue.js
- SOAP API
- GraphQL
- Vue
- 알고리즘
- Repository Pattern
- 백준
- 파이썬
- js
- Preloading
- error
- Vuex
- 프로그래머스
- bundler
- redux
- clean code
- 상호평가
- programmers
- AxiosInterceptor
- React.memo
- reactrouter
- Transpiler
- SPA
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |