성능이란?
- Latency: 작업 하나의 완료 시간 (시간 단위)
- Throughtput: 일정 시간동안 완료한 작업의 양(시간단위당 작업)
멀티스레드로 응답시간 최적화
T(싱글 스레드에서의 작업시간)/N(스레드 수)
- N은 몇 개까지 가능한가?
- 코어의 개수가 가장 이상적 (모든 스레드가 인터럽트 없이 실행)
- 스레드가 하나라도 많아지면 컨텍스트 스위치, 캐시성능저하, 추가메모리 소비를 유발
- IO도 블로킹도 없이 모든 스레드가 runnable 상태를 유지하는 것은 비현실적
- 더불어 요즘은 하이버스레딩을 통해 코어당 두개의 가상스레드로 병렬처럼 실행할 수 있음
- 각 스레드의 결과를 합치는 코스트
- 작업을 세그먼트로 나누는 작업, 스레드 생성비용, 시작비용, 운영체제 스케줄링 비용, 집계완료 시그널 대기 시간, 결과 병합 작업
- 응답시간 테스트를 통해 트레이트 오프가 필요함
- 어떤 작업이든 분할이 가능한가?
- Parallelizable task 인지 Sequential task 인지 부분적인지 확인 필요
멀티스레드로 처리량 최적화
1(시간단위)/T(하나의 작업을 처리하는 시간) -> N/T
subtask 로 쪼개 병렬실행 하는 방법 : N/T 처리량, 지연시간최적화같은 처리량과 무관한 작업이 들어가기 때문에
별개 스레드에 스케줄링 하는 방법: 작업을 서브테스크로 나누고, 결과를 병합하는 작업이 등이 없어져 최적의 처리량을 낼 수 있음. 매 작업마다 스레드를 재생성할 필요 없음
Thread pooling
따라서 queue와 풀, 적절한 작업 분할을 통해 최적의 처리량과 응답시간을 얻어야함
스레드간 데이터 공유
stack
- 메서드가 실행되는 메모리 영역
- 함수에 전달된 인자, 로컬 변수 등이 저장
- 호출 순서대로 스택 프레임에 저장되고 메서드가 끝나면 사라짐
heap
- Java 내장 클래스 문자열, 객체, 컬렉션, 정적 변수 등
- 스레드 간 공유
- JVM GC 관리 대상
stack & heap
리소스 공유와 임계영역
- 리소스: 데이터, 어떤 상태...
- 정수나 문자열 같은 간단한 변수
- 데이터 구조 배열, 컬렉션, 맵이나 파일을 나타내는 객체
- 네트워크나 데이터베이스에 대한 연결에 해당하는 객체, 메시지 큐 등
공유 리소스의 장점
Queue는 힙에 저장된 공유리소스기때문에 새 작업이 생길 때마다 매번 새 스레드를 다시 만들 필요가 없어 효율적으로 CPU를 활용하고 지연 시간도 늦출 수 있음
데이터베이스가 하나뿐이므로 반드시 공유되는 연결이 있어야 하지만 항상 많은 수의 독립된 요청이 유입 가능
임계영역
OS의 스케줄링에 따라 공유자원에 접근하는 여러 스레드의 실행 순서가 달라진다면 의도치 않은 결과가 나올 수 있음