L1과 L2 같은 캐시는 물리 코어에 종속되어 있어 모든 논리 코어가 공유할 수 없음
→ 이런 특성은 동시성과 거짓 공유 등에 영향을 끼침
type Input struct {
a int64
b int64
}
type Result struct {
sumA int64
sumB int64
}
// Input 배열을 받아서 Input.a의 합을 Result.sumA에, Input.b의 합을 Result.sumB에 저장하는 기능
func count(inputs []Input) Result {
wg := sync.WaitGroup{}
wg.Add(2)
result := Result{}
// 두 개의 고루틴을 사용해 각각 sumA와 sumB를 계산
go func() {
for i := 0; i < len(inputs); i++ {
result.sumA += inputs[i].a
}
wg.Done()
}()
go func() {
for i := 0; i < len(inputs); i++ {
result.sumB += inputs[i].b
}
wg.Done()
}()
wg.Wait()
return result
}
거짓 공유란?
sumA와 sumB는 메모리상에서 연속적으로 배치되기 때문에, 이 두 값은 같은 캐시 라인에 저장될 가능성이 높음
두 개의 CPU 코어가 있을 때, sumA와 sumB가 포함된 메모리 블록이 각각의 캐시로 복사됨
각 코어에서 고루틴이 독립적으로 sumA와 sumB를 업데이트하지만, 캐시 라인 단위로 동기화를 해야 하므로 캐시 라인이 무효화돼 성능 저하가 발생
⇒ 변수가 독립적으로 사용되는 것처럼 보이지만, 실제로는 같은 캐시 라인에 있기 때문에 CPU는 두 변수를 하나로 묶어 동기화를 처리
패딩추가
type Result struct {
sumA int64
_ [56]byte // Padding
sumB int64
}=[-
채널을 사용한 구조 변경