캐시 지역성
최근에 사용했던 데이터와 인접한 데이터가 참조될 가능성이 높다는 특성으로
캐시가 효율적으로 동작하기 위해 사용되는 성질이다.
실험 환경
Windows 10
C# 유니티
실험방법
2중 for문을 돌려 인덱스 접근을 다르게 한다.
하나는 i, j / 하나는 j, i로 접근
i, j 반복

실험코드
using System;
using System.Collections.Generic;
using UnityEngine;
public class TimeTester : MonoBehaviour
{
void Start()
{
int repeat = 5000;
CheckTime(() =>
{
int[,] arr = new int[repeat, repeat];
for (int i = 0; i < repeat; i++)
{
for (int j = 0; j < repeat; j++)
{
arr[i, j] = 0;
}
}
}, "i, j", 10);
}
private void CheckTime(Action action, string testName, int repeat)
{
double sum = 0;
for (int i = 1; i <= repeat; i++)
{
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
action();
watch.Stop();
sum += watch.ElapsedMilliseconds;
Debug.Log(testName + "반복" + i + ": " + repeat + ", 시간: " + watch.ElapsedMilliseconds + "ms");
}
Debug.Log(testName + "평균: " + sum / repeat + "ms");
}
}
j, i 반복

실험코드
using System;
using System.Collections.Generic;
using UnityEngine;
public class TimeTester : MonoBehaviour
{
void Start()
{
int repeat = 5000;
CheckTime(() =>
{
int[,] arr = new int[repeat, repeat];
for (int i = 0; i < repeat; i++)
{
for (int j = 0; j < repeat; j++)
{
arr[j, i] = 0;
}
}
}, "j, i", 10);
}
private void CheckTime(Action action, string testName, int repeat)
{
double sum = 0;
for (int i = 1; i <= repeat; i++)
{
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
action();
watch.Stop();
sum += watch.ElapsedMilliseconds;
Debug.Log(testName + "반복" + i + ": " + repeat + ", 시간: " + watch.ElapsedMilliseconds + "ms");
}
Debug.Log(testName + "평균: " + sum / repeat + "ms");
}
}
결과
i, j 반복 평균: 119ms
j, i 반복 평균: 154ms
5000 X 5000일경우 j, i 순으로 탐색하면 계속 int * 5000사이즈만큼 떨어진 메모리를 참조하기 때문에
캐시메모리 지역성이 활용되기가 어렵다.
추가실험
캐시 메모리 지역성때문에 속도차이가 난다면
배열 크기를 작게해서 실험한다면 속도가 비슷하지 않을까?
더보기

실험방법
배열의 크기를 2 X 2로 만들어 위와 같이 i, j 순서를 바꿔 반복시켜 본다.
결과
별 차이가 없다.
배열 크기가 작아서 반대로 해도 지역성 특성을 이용할 수 있는 것 같다고 추측된다.


실험 코드
using System;
using System.Collections.Generic;
using UnityEngine;
public class TimeTester : MonoBehaviour
{
void Start()
{
int repeat = 2;
CheckTime(() =>
{
for (int k = 0; k < 500000; k++)
{
int[,] arr = new int[repeat, repeat];
for (int i = 0; i < repeat; i++)
{
for (int j = 0; j < repeat; j++)
{
arr[i, j] = 0;
}
}
}
}, "i, j", 10);
CheckTime(() =>
{
for (int k = 0; k < 500000; k++) {
int[,] arr = new int[repeat, repeat];
for (int i = 0; i < repeat; i++)
{
for (int j = 0; j < repeat; j++)
{
arr[j, i] = 0;
}
}
}
}, "j, i", 10);
}
private void CheckTime(Action action, string testName, int repeat)
{
double sum = 0;
for (int i = 1; i <= repeat; i++)
{
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
action();
watch.Stop();
sum += watch.ElapsedMilliseconds;
Debug.Log(testName + "반복" + i + ": " + repeat + ", 시간: " + watch.ElapsedMilliseconds + "ms");
}
Debug.Log(testName + "평균: " + sum / repeat + "ms");
}
}
100% 지역성 때문이다 라고 하기엔 모르는게 많아서 말하긴 어렵겠지만
어느정도 영향이 있다고 추측된다.
'C#' 카테고리의 다른 글
| 박싱 언박싱 성능 체크 기록 (0) | 2024.01.31 |
|---|---|
| [C#] Generic 함수 타입 변수로 지정하기 (0) | 2023.10.25 |
| [C#] 스택(Stack), 큐(Queue) 속도 차이 (0) | 2022.06.23 |