프로세스 : 시스템에서 수행되는 작업의 단위
스레드 : CPU를 이용하는 기본 단위
스레드는 자신만의 스레드 ID, PC, 레지스터 집합, 스택을 가진다.
멀티 프로세스는 코드, 데이터, 힙, 스택을 전부 새로 만들어야하지만, 멀티 스레드는 코드, 데이터, 힙을 새로 만들지 않아도 돼서 성능상으로 이득.
그럼 멀티 프로세스는 언제 쓰냐?
- 프로세스간 독립적인 메모리 공간을 써야할 경우 ex. 완전히 다른 프로그램
- 에러 전파를 막고싶은 경우 ex. 한 탭에서 에러난다고 다른 탭까지 에러 안남
서버가 요청을 받아들이는 하나의 프로세스로 동작하게 한다.
클라이언트가 서버에게 커넥션 요청을 할 때, 그 요청을 listen하는 스레드를 생성한다. 커넥션마다 새로 프로세스를 만든다면 성능 손해. (Nginx가 아파치보다 커넥션 생성 성능 좋은 이유)
병행 vs 병렬
- 병행은 유저에게 두 개의 작업을 동시에 제공할 수 있는 것을 의미. 근데 무조건 동시에 실행되는 건 아니고, cpu 왔다갔다하면서 동시에 제공하는 것처럼 보이는 걸 의미
- 병렬은 ㄹㅇ 동시 실행 (멀티 코어) 병령이 더 쎈 개념. 병렬없이 병행을 수행할 수 있다.
사용자 스레드와 커널 스레드의 매핑 전략
유저 스레드(다) - 커널 스레드(일)
한 번에 하나의 스레드만 커널 사용할 수 있기 때문에 별로임. 잘 안쓰임
유저 스레드(일) - 커널 스레드(일)
사용자 스레드 만들려면 커널 스레드 무조건 만들어야함. 많은 수의 커널 스레드 필요.
그러나 일반적으로 사용되는 모델임. 코어 수가 늘어나면서 커널 스레드 수를 제한하는 것의 중요성이 줄어들었기 때문.
유저 스레드(다) - 커널 스레드(다)
일대일 모델보다 적은 양의 커널 스레드를 생성할 수 있지만 구현이 까다롭다.
비동기 스레딩은 부모와 자식 스레드가 독립적으로 실행
스레드가 독립적이라서 스레드 사이 데이터 공유는 거의 없는 편
동기 스레딩은 부모 스레드가 자식 스레드가 모두 종료될 때까지 기다렸다가 조인함. 부모 스레드는 조인 후에 실행을 재개할 수 있음. ex. 분할 정복 알고리즘 - 포크 조인
스레드의 생성과 관리 책임을 개발자로부터 컴파일러와 라이브러리에게 넘겨버리는 것을 의미
개발자는 병렬로 수행할 작업만 식별하고, 라이브러리가 스레드를 생성하고 관리하거라~
미리 스레드 만들어서 스레드 풀에 넣어둠. 스레드 필요할 때 스레드 풀에서 가져와서 씀.
부모 프로세스가 자식 프로세스를 만들어 일 시키고, join해서 결과 반환.
포크 조인 구현할 때는 어느 시점까지 fork를 수행할 것인가 결정하는 게 중요. (재귀 함수니까 당연)
자바의 경우, 자료 구조마다 포크 기준을 정하는 인터페이스를 구현하고 있음.
자바에서 스레드를 명시적으로 생성하는 두 가지 방법
얘네 둘은 저수준 API라 불편함이 존재함.
Runnable은 스레드 수행 결과 반환 불가능.
Callable은 스레드 수행 결과를 Future 형태로 반환.
스레드 객체를 명시적으로 생성하는 대신 Executor 인터페이스를 중심으로 스레드 생성을 구성 (new Thread(RunnableImpl)) 안해도 됨.
스레드 풀 생성 지원. 개발자는 스레드 풀 설정만 하면, 라이브러리가 알아서 스레드 생성 및 스케줄링.
스레드 생성을 실행에서 분리.
병행하게 실행되는 작업간의 통신 기법을 제공??? 뭔 소리지