
A라는 인간은 모니터 2대를 활용하여 오른쪽 모니터에는 공부자료를 띄워놓고 책상에는 필기노트가 있으며 왼쪽 모니터에는 유투브 영상이 틀어져있다. 이런 것을 우리는 멀티태스킹이라고 하지만, 실제로는 왼쪽 모니터를 볼 때는 오른쪽 모니터를 볼 수는 없다. 즉 짧은 시간동안 눈은 모니터 2대와 필기노트를 왔다갔다 한다.
컴퓨터의 멀티태스킹도 동일한 논리를 가진다. 두 프로그램만 실행된 환경이라고 가정할 때에 CPU코어는 매우 빠르게 두 프로그램의 코드를 번갈아 수행한다. CPU코어가 너무 빨라 인간은 이 두 프로그램이 동시에 실행되는 것 처럼 느낀다.
이렇게 각각의 프로그램의 실행 시간을 분할하여 동시에 실행되는 것 처럼 보이게 하는 기법을 시분할(time sharing)기법이라고 한다.

위의 인간의 관점에서의 비유에서는 시각적으로만 한정지어서 멀티태스킹을 설명했다. 하지만 인간에게는 많은 감각(코어)가 존재한다. 우리는 공부화면을 보면서 유투브는 귀로 듣기도 한다.
만약 공부화면을 보면서 유투브 영상은 귀로 들으며 두 정보를 모두 동시에 처리하고 있다면 그 사람은 멀티태스킹의 장인이 아니라 멀티프로세싱 인간이라 불러야 할 것이다.
컴퓨터 또한 현대의 보통적인 CPU는 여러 코어를 가진다. 멀티 프로세싱은 하드웨어의 관점에서의 개념이다. 둘 이상의 CPU코어(프로세서)를 사용하여 여러 작업을 동시에 처리하는 기술을 말한다.
프로그램은 실제 실행 전까지 단순한 파일에 불과하며 이 파일을 실행하는 순간 프로세스가 만들어지고 프로그램이 실행된다. 실행중인 프로그램을 프로세스라고 지칭한다.
자바로 비유하자면 클래스는 프로그램이며 인스턴스는 프로세스이다.
각 프로세스는 독립적이다.
프로그램이 실행되면 메모리에 프로그램의 정보들이 올라간다.(프로세스 생성)
프로세스는 하나 이상의 스레드를 반드시 포함한다. 스레드는 프로세스 내에서 실행되는 작업의 단위이다.
같은 프로세스내에 있는 스레드는 생성 및 관리가 단순하다(스택 부분만 가지고 나머지는 프로세스의 자원을 사용한다.)
하지만 스레드는 프로세스처럼 독립적이지 않다. 같은 프로세스 내부의 스레드들은 프로세스의 자원을 공유하므로 서로에게 영향을 줄 수 있다.
하나의 프로그램도 그 안에서 동시에 여러 작업이 필요하다.
현재 글을 쓰는 이 블로그 웹 어플리케이션 또한 글을 쓰면서 동시에 임시저장 기능도 작동한다.
사용자가 일정 시간마다 직접 저장하지 않아도, 백그라운드에서 일정 주기마다 서버에 자동으로 저장 요청을 보내는 것이다. 이는 사용자가 눈치채지 못하는 사이에 별도의 쓰레드가 작동하고 있다는 의미이기도 하다.
실제로 운영체제는 CPU코어로 하여금 프로세스 단위로 스케줄링 하는 것이 아니라 쓰레드 단위로 스케줄링을 진행한다.
모든 스레드는 여기서 줄을 서게 되고 CPU의 코어들은 이를 OS의 스케줄링 알고리즘에 따라 처리한다.

리눅스 커널 개발자에게 누군가 “스레드와 프로세스는 명확히 구분되어야 하지 않느냐”고 묻자, 그는 “굳이 그렇게 나눌 필요는 없다”고 답했다. 실제로 리눅스에서는 스레드와 프로세스를 구조적으로 동일하게 다루며, 내부적으로는 모두 태스크(task) 로 처리된다.

즉 멀티태스킹의 개념과 멀티프로세싱의 개념과 스레드, 프로세스의 개념을 모두 파악했다면 현대의 우리가 일반적으로 사용하는 CPU에서 어떤 일이 발생하는 지 대략적으로 파악이 가능하다.
멀티코어는 스케줄링 큐에 존재하는 스레드(from프로세스)들을 스위칭하며 처리하는 것이다.
실제로 여러 작업을 병렬로 처리하는 다중 코어 기반의 방식과, 하나의 코어에서 빠른 시간 분할로 동시성처럼 보이게 하는 방식(시분할 방식)이 함께 사용된다.
컨텍스트 스위칭은 멀티태스킹에 관련한 비용이다.
멀티프로세싱(진짜 동시에 처리)과 다르게 멀티태스킹(동시처럼 보이게 빠르게 왔다갔다 처리)은 "왔다갔다"에서 비용이 발생한다.
스레드를 처리하다가 스케줄링 알고리즘에 의해 완벽히 처리하지 못하고 다시 스케줄링 큐에 넣어야할 때 프로세서(코어)는 다음 스레드를 꺼내오면서 이런저런 일들을 한다.(꺼내온 스레드가 어디서 부터 실행해야할지 조회도 할 것이며 다시 큐에 넣은 스레드에 다시 코어로 올때 해야할 작업들을 설정하는 등의 일을 한다.)
사람으로 비유할 경우 잔뜩 집중해서 어떤 문제를 풀다가 누군가가 잠시 도와달라고 한다면 그 사람을 도와주고 다시 집중해서 풀던 문제로 돌아갈 때, 집중해서 풀던 그 집중상태가 해이해진다.
책을 읽다가 방해를 받았다면 이전의 스토리가 무엇이었는지 다시 떠올려야 하고 읽었던 부분이 어딘지 다시 찾아야 한다.
즉 이러한 스위칭 비용이 컴퓨터의 멀티태스킹에도 존재하고 이것을 컨텍스트 스위칭이라고 한다.
보통의 경우 멀티스레드는 효율적이다.(90%이상의 경우에)
다음의 예시는 해당 CPU자원을 사용하는 프로그램은 하나라고 가정한다.
CPU 코어 8개 시스템, 스레드 2개 프로그램
스레드가 2개 이므로 컨텍스트 스위칭은 필요없을 것이다. 8개의 CPU 코어중 2개만 작동하여 각 스레드를 계속 담당할 수 있다.
CPU 코어 8개 시스템, 스레드 1000개 프로그램
코어에 비해 스레드가 굉장히 많으므로, 각 코어들은 1000개의 스레드를 동시에 실행시키는 것 처럼 보이게 하기 위해 8개가 1000개의 스레드를 계속 전환하며 실행시킬 것이다. 이전 예시에 비해 굉장히 많은 컨텍스트 스위칭 비용이 발생한다.
CPU 코어 8개 시스템, 스레드 8개
스레드의 숫자를 CPU에 맞춘다면 CPU를 100% 활용하면서도 컨텍스트 스위칭 비용을 최소화 할 수 있다. 이상적으로는 CPU 코어 수 + 1개정도로 특정 스레드가 잠시 대기할 때 남은 스레드를 활용할 수 있다.
그렇다면 우리는 프로그램의 스레드를 CPU 코어 수에 수렴하도록 설계해야할까?
보통은 스레드를 훨씬 많이 사용한다.
CPU bound tasks는 CPU의 연산 능력을 많이 요구하는 작업을 의미한다. 주로 계산 및 데이터 처리 등의 복잡한 처리의 작업을 말한다.
이러한 작업은 CPU가 할 일이 당연히 많을 것이다. 반면 I/O bound tasks는 입출력 작업을 많이 요구하는 작업을 의미하며 이러한 작업에는 DB 쿼리 처리, 파일 읽기/쓰기, Http통신 등이 있다.
실제로 프로그램의 백엔드에서 일어나는 일들은 CPU bound tasks보다 I/O bound tasks들이 많다. I/O bound tasks은 스레드가 CPU를 사용하지 않고 I/O 작업이 완료될 때 까지 대기하는 시간이 굉장히 많다.
만약 스레드 수와 코어 수를 맞춘다는 법칙으로, CPU 코어만큼 스레드를 코어수에 수렴하도록 설계했더니 실상은 해당 스레드들이 높은 비율로 쉬고 있을 경우가 많다면 CPU 점유율은 내려갈 것이다.
프로그램의 스레드를 적절하게 설정하는 것은 그러므로 우리가 설계할 프로그램이 어떤 로직들을 가지고 있느냐도 중요할 것이고 어떤 경우에 놓였을 때에 대해서도 생각해야한다.
그러므로 스레드 수에 대한 성능테스트가 필요하다.