의 내용처럼 단지, 멀티태스킹이 무조건 효율적인가? 그건 또한 아니다.
예를들어, 만약 내가 프로그램 A를 개발하고 있는데, 기획자가 프로그램B를 수정해달라고 한다. 그리고 내가 프로그램B를 수정하고 다시 프로그램 A로 돌아온다면 내가 어디 개발하는지 어떤 변수인지 헷갈릴테며, 다시 내 머리속으로 불러와야한다. 만약 프로그램 A를 다 개발이 끝나고 프로그램 B를 수정한다면, 전체 시간으로 보면 더 효율적으로 개발할 수 있을 것이다.이는 사람에 비유한 것이며,
그렇다면 운영체제의 멀티태스킹을 생각해보자.
예들들어, CPU 코어는 1,스레드A,스레드B가 있다. 운영체제는 먼저 스레드A를 실행한다. 멀티태스킹을 해야하기에, 스레드A를 계속 실행할 수가 없다. 그렇기에 잠시 스레드A를 멈추고 스레드B를 실행한다. 이후 스레드A로 그냥 돌아갈 수 없다. CPU에서 스레드를 실행하는데, 스레드A의 코드가 어디까지 수행되었는지 위치를 찾아야 한다.
따라서, 스레드A를 멈추는 시점에 CPU에서 사용하던 이런 값들을 메모리에 저장해두어야 한다. 그리고 이후에 스레드A를 다시 실행할 때 이 값들을 CPU에 다시 불러들인다. -> 이를 컨텍스트 스위칭이라고 한다.
이렇듯 이전에 실행 중인 값을 메모리에 저장후, 이후에 다시 실행하는 시점에 저장한 값을 CPU에 불러와야한다. 그렇기에 결국엔 컨텍스트 스위칭 과정에서 약간의 비용이 발생한다.
"멀티태스킹이 반드시 효율적인 것 만은 아니다."로 다시 돌아온다면, 이는 컨텍스트 스위칭 과정이 필요하므로 항상 효율적이지는 않다는 의미이다.
예를 들면, 1~10000까지 더해야한다고 했다면,
스레드1 : 1~5000더함
스레드2: 5001~10000더함
이렇게 스레드 2개가 1~10000을 더하는 것을 나뉘어서 한다면, 결국엔 컨텍스트 스위칭이 일어날 것이며, 추가적인 비용이 발생하는 것이다. 그냥 스레드 한개가 다 처리하면 추가적인 비용이 발생하지 않을텐데 말이지.
이렇게 예를 들었으나, 실제 컨텍스트 스위칭에 걸리는 시간은 매우매우 짧다. BUT, 스레드가 매우 많다면 이 비용이 커 질 수가 있다. 물론 최신 CPU는 초당 수 십억 단위를 계산하기 때문에 실제로는 계산에 더 큰 숫자를 사용해야 컨텍스트 스위칭이 발생한다.
✔️실무에서 발생되는 이야기
각각의 스레드가 하는 작업은 크게 2가지로 나뉘어진다.
📍 CPU-바운드 작업
- CPU의 연산 능력을 많이 요구하는 작업을 의미한다.
- 이러한 작업은 주로 계산, 데이터 처리, 알고리즘 실행 등 CPU의 처리 속도가 작업 완료 시간을 결정하는 경우다.
- 예시: 복잡한 수학 연산, 데이터 분석, 비디오 인코딩, 과학적 시뮬레이션 등
📍 I/O-바운드 작업 (I/O-bound tasks)
- 디스크, 네트워크, 파일 시스템 등과 같은 입출력(I/O) 작업을 많이 요구하는 작업을 의미한다.
- 이러한 작업은 I/O 작업이 완료될 때까지 대기 시간이 많이 발생하며, CPU는 상대적으로 유휴(대기) 상태 에 있는 경우가 많다. 쉽게 이야기해서 스레드가 CPU를 사용하지 않고 I/O 작업이 완료될 때 까지 대기한 다.
- 예시: 데이터베이스 쿼리 처리, 파일 읽기/쓰기, 네트워크 통신, 사용자 입력 처리 등.
✔️웹 어플리케이션 서버
백엔드의 실무에서는 CPU-바운드 작업보다는 I/O-바운드 작업이 훨씬 더 많다. 대부분 사용자의 입력을 기다리거나, 데이터를 조회할때 그 결과들을 기다리는 로직들이 많기 때문이다.
일반적으로 자바 웹 어플리케이션의 경우 사용자의 요청에 하나의 스레드가 할당이된다. 만약 사용자의 요청 하나를 처리하는데 cpu가 1%정도 사용하고, DB에 어떠한 결과를 조회하면서 기다린다고 가정한다. 그랬을때, 사용자가 4명있때, 스레드 4개가있을텐데, cpu가 총 4퍼가 사용되니 cpu가 거의 사용하지않는다. 바로 I/O 작업이 많다는 의미이다.
이 경우 CPU 코어가 4개 있다고해서 스레드 숫자도 CPU 코어에 맞추어 4개로 설정하면 안된다! 그러면 동시에 4명의 사용자 요청만 처리할 수 있다. 이때 CPU는 단순하게 계산해서 4% 정도만 사용할 것이다. 결국 사용자는 동시에 4명 밖에 못받지만 CPU는 4%만 사용하며 CPU가 놀고 있는 사태가 벌어질 수 있다.
그렇기에 실무에서는 성능 테스트를 통해서 최적의 스레드 숫자를 찾는 것이 매우 이상적이다.
정리하면 아래와 같다.
📍 CPU-바운드 작업
- CPU 코어 수+ 1개
- CPU를 거의 100% 사용하는 작업이므로 스레드를 CPU 숫자에 최적화
📍 I/O-바운드 작업
- CPU 코어 수보다 많은 스레드 생성, cpu를 최대한 사용할 수 있는 숫자까지 스레드 생성
- CPU를 많이 사용하지 않으므로 성능 테스트를 통해 CPU를 최대한 활용하는 숫자까지 스레드 생성
- 단 너무 많은 스레드를 생성하면 컨텍스트 스위칭 비용도 함께 증가 - 적절한 성능 테스트 필요