논리 프로세서와 멀티뜨레드
cpu를 만드는 기술은 연산 능력을 높이는 대신 크기를 줄이는 방향으로 발전하고 있다. 그게 더 쉽기 때문이다. 더 조그매진 cpu들 여러 개를 한데 묶어 하나의 칩으로 만든다. 이게 멀티-코어 프로세서다. 하나의 부속이지만 그 안에는 물리적으로 구분되는 여러 cpu들이 코어라는 이름으로 들어 있다.
하나의 작업을 여럿으로 나눠 처리하는 것을 멀티뜨레딩이라 한다. 흔히들 알고 있는 것과는 달리 멀티뜨레딩이 꼭 동시concurrent, parallel 처리를 의미하는 것은 아니다. 하나의 순서로 처리되는 작업을 두 개 이상의 cpu, 코어, 뜨레드로 나누어 시분할serial time slice 처리를 할 수도 있다. cpu에 크게 부하를 주는 연산을 실행하면 비록 싱글 뜨레드로 작성된 거라 해도 윈도우즈는 여러 뜨레드로 나누어 처리한다. 그러나 여러 cpu 점유율의 합은 ‘1/물리적 코어의 수’를 넘지 않는다. 동시 처리가 아니기 때문이다.
순수하게 cpu 부하만을 만들기 위한 아무 의미 없는 아래의 코드는, 6개의 코어들이 있고 12개의 논리 프로세서들이 있는 내 컴퓨터에서 8개의 cpu로 나누어져 같은 수의 뜨레드 실행되고 있다. 하지만 cpu 점유율은 1/6인 16~17%를 유지한다. 잠깐씩 17%를 넘기도 하는데 이는 싱글 뜨레드로 만들어도 기본적으로 돌아가는 독립 뜨레드들이 있기 때문이며 이들이 차지하는 연산 점유이다. 이들은 주된 연산을 하는 게 아닌 보조적인 것들이므로 잠깐 작동하고 바로 수그러든다.
private void Form1_Load(object sender, EventArgs e) { for (int i = 0; i < 10000000000; i++) { for (int j = 0; j < 10000000000; j++) { for (int k = 0; k < 10000000000; k++) { for (int l = 0; l < 10000000000; l++) { double double1 = default; try { double1 = i * j * k * l / i / j / k / l; Text = double1.ToString(); } catch (Exception) { Text = "abcde"; } } } } } }

각 코어에서는 우리가 실행하지 않은 여러 자잘한 프로세스들이 이미 돌아가고 있다. 만약 윈도우즈가 위와 같은 자동적 멀티뜨레드를 구현하지 않으면 높은 cpu 점유를 하는 하나의 프로세스는 하나의 코어를 먹통으로 만들 것이다. 그러면 이 하나만 멈추는 게 아니라 그 전에 돌고 있던 다른 프로세스들도 다 멈춘다. 이상이 넓은 의미의 멀티뜨레드다.
좁은 의미의 멀티뜨레드는 동시 처리를 의미한다. 동시 처리는 필연적으로 멀티뜨레딩이다. 위 예제의 루프들을 병렬 루프로 바꾸어 실행하면 이 프로세스 하나가 cpu를 완전하게 다 쓸 수 있다. 물론 컴퓨터는 사용 불가에 가깝게 멈추겠지만 연산은 빨리 끝날 것이다. 엄격하게는 병렬 루프가 꼭 연산 시간을 단축한다는 보장은 없지만 …
위 예제에서 눈길을 끄는 것은 논리 프로세서logical processors의 구분이다. 12개의 논리 프로세서들이 각자 하나의 프로세서로서 기능을 한다면 위 예제는 1/6이 아닌 1/12이어야 할 텐데 보다시피 프로세서의 논리적 구분은 별 의미가 없다는 걸 알 수 있다.