멀티쓰레드 이론
멀티쓰레드 이론 시간에 이와 같이 비유했었다.
식당이 있는 곳-> 유저 모드
관리자가 있는 곳-> 커널 모드
로봇 직원: 쓰레드
식당: 프로세스
영혼: CPU 코어
평상시 손님 수라면 문제가 없겠지만, 만약 손님들이 너무 많아 진다면 일처리가 어려울 것이다. 주문이 갱신될 때마다 항상 테이블과 주문 현황표를 오고 가기는 정말 어려울 테니 말이다. 그래서 한 가지 생각을 한다
주문을 수첩에다가 메모하고, 한 번에 주문 현황에 올리는 건 어떨까?
그러니까 콜라를 주문했다고 주문 현황표에 바로 올리지 않고, 다른 주문들도 수첩에 적다가 이를 주문 현황표에 올리는 것이다.
만약에 이렇게 하면 만일 콜라가 아니라 사이다를 주세요라고 번복 주문을 했더라도 수첩에서 바로 지우면 문제가 없으니 말이다.
수첩: 캐시
주문 현황표: RAM
CPU 내엔 여러 개의 코어가 있고 그 코어 내엔 ALU(산술연산장치)와 캐시가 존재한다. 보통 정보는 메인 메모리에 저장되지만, 더 빠른 장치인 캐시에 저장되어 있는걸 꺼내 쓴다면 훨씬 빠르게 정보를 접근할 수 있을 것이다.
(다른 말로 이야기하면, 찾고자 하는 정보가 캐시에 없으면 직접 메인 메모리에 갔다와야 한다는 말.)
캐시에 대한 철학은 두 종류가 있다.
TEMPORAL LOCALITY(시간 지역성)
->시간적으로 보면, 방금 주문한 테이블에서 추가 주문이 나올 확률이 높으니, 방금 주문한 걸 메모해놓자.
SPACIAL LOCALITY(공간 지역성)
->공간적으로 보면, 주문한 사람 근처 사람, 테이블 사람이 추가 주문을 할 확률이 높으니, 이 사람들의 주문 목록도 메모해놓자.
이를 확인할 수 있는 예제를 살펴보자.
using System;
using System.Collections.Generic;
using System.Text;
namespace ServerCore
{
class cache
{
static void Main(string[] args)
//첫번째: 순차적으로 앞으로 간다. 1,2,3,4,5.... SPACIAL LOCALITY
//바로 옆에 있는건 캐시에 미리 저장
//두번째: 1, 6, 11, 16.... 순으로 띄엄띄엄 접근. 그다음 2,7,...
//공간적 이점아님.
{ //[][][][][] [][][][][]... 5*5 배열
int[,] arr = new int[10000, 10000];
{
long now = DateTime.Now.Ticks;
//시간이 얼마나 걸리나
for(int y = 0; y < 10000; y++)
{
for(int x = 0; x < 10000; x++)
{
arr[y, x] = 1;
}
}
long end = DateTime.Now.Ticks;
Console.WriteLine($"(y,x) 순서 걸린 시간: {end-now}");
}
{
long now = DateTime.Now.Ticks;
for (int y = 0; y < 10000; y++)
{
for (int x = 0; x < 10000; x++)
{
arr[x, y] = 1;
}
}
long end = DateTime.Now.Ticks;
Console.WriteLine($"(x,y) 순서 걸린 시간: {end - now}");
}
}
}
}
단순히 이차원 배열을 동적 할당한 다음, 값을 1 대입하는 예제문이다.
두 코드 블록을 보면 결과적으로 보면 사실상 같은 결과일 것이다. DateTime을 이용하여 두 코드가 얼마나 오래 걸리는지 출력해보자.
시간이 꽤나 차이가 난다. 이유는 무엇일까?
첫 번째 예제는 y=0이고, x가 증가한 상태에서 다음과 같이 값이 갱신될 것이다.
arr[0,1]=1, arr[0,2]=1...
두 번째 예제는 이와 같이 값이 들어갈 것이다.
arr[0,0]=1, arr[1,0]=1...
배열은 배열의 요소들이 메모리에 연속적으로 할당되는 것이 특징인 걸 알고 있자.
첫 번째 예제는 두 번째 예제와 다르게 가장 가까운 메모리 공간에 연속적으로 접근하는 모습을 확인할 수 있다. 따라서 공간 지역성 특성상 해당 정보가 캐시에 미리 저장되어 있기 때문에, 두 번째 예제보다 더 빠르게 작동할 수 있다.