>  기사  >  백엔드 개발  >  Go 언어의 확장 방법은 무엇입니까?

Go 언어의 확장 방법은 무엇입니까?

青灯夜游
青灯夜游원래의
2023-01-16 16:11:581565검색

Go 언어 확장 방법은 다음과 같습니다. 1. 슬라이스 확장. 추가를 사용하여 슬라이스에 요소를 추가할 때 슬라이스 공간이 부족하면 슬라이스 확장이 실행됩니다. 맵 확장을 트리거하는 조건은 두 가지입니다. 1. 로드 요소가 6.5보다 큰 경우, 즉 각 버킷에 저장된 키-값 쌍의 평균 개수가 6.5에 도달하는 경우 2. 오버플로 수가 2^보다 큰 경우 15, 즉 오버플로 횟수가 32768을 초과하는 경우입니다.

Go 언어의 확장 방법은 무엇입니까?

이 튜토리얼의 운영 환경: Windows 7 시스템, GO 버전 1.18, Dell G3 컴퓨터.

슬라이스 확장

triggers

슬라이스에 요소를 추가하기 위해 append를 사용할 때 슬라이스 공간이 부족하면 슬라이스 확장이 시작됩니다.

Principle

확장은 실제로 더 큰 메모리를 재할당하는 것을 의미합니다. 슬라이스 데이터는 새 슬라이스에 복사된 후 새 슬라이스로 반환되고 확장 후 데이터가 추가됩니다.

메커니즘

V1.8 이전:

확장 용량 선택은 다음 규칙을 따릅니다.

  • 원래 슬라이스 용량이 1024보다 작으면 새 슬라이스 용량은 원래의 2배로 확장됩니다.
  • 원래 슬라이스 용량이 1024보다 크면 새 슬라이스 용량은 원래의 1.25배로 확장됩니다.
// 1.17及以前的版本中
// old指切片的旧容量, cap指期望的新容量
func growslice(old, cap int) int {
    newcap := old
    doublecap := newcap + newcap
    // 如果期望容量大于旧容量的2倍,则直接使用期望容量作为最终容量
    if cap > doublecap {
        newcap = cap
    } else {
        // 如果旧容量小于1024,则直接翻倍
        if old < 1024 {
            newcap = doublecap
        } else {
            // 每次增长大约1.25倍
            for 0 < newcap && newcap < cap {
                newcap += newcap / 4
            }
            if newcap <= 0 {
                newcap = cap
            }
        }
    }
    // 这里忽略了对齐操作
    return newcap
}
V1.8 이후:

새 확장 용량 선택은 다음 규칙을 따릅니다. 더 부드러운 확장 계수)

    원래 슬라이스 용량이 256보다 작은 경우 새 슬라이스 용량은 원래 크기의 2배로 확장됩니다.
  • 원래 슬라이스 용량이 256보다 크거나 같으면 새 Slice 용량은 원래 크기로 확장됩니다.
  • 새 용량 = (원래 용량 + 3*256)/4
  • // 只关心扩容规则的简化版growslice
    func growslice(old, cap int) int {
        newcap := old
        doublecap := newcap + newcap
        if cap > doublecap {
            newcap = cap
        } else {
            const threshold = 256 // 不同点1
            if old < threshold {
                newcap = doublecap
            } else {
                for 0 < newcap && newcap < cap {
                    newcap += (newcap + 3*threshold) / 4 // 不同点2
                }
                if newcap <= 0 {
                    newcap = cap
                }
            }
        }
        return newcap
    }

Map 확장

expansion을 실행하는 두 가지 조건이 있습니다.

  • load 즉, 각 버킷에 저장된 키-값 쌍의 평균 개수는 6.5에 도달합니다.

    IncrementExpansion

  • 오버플로 수가 2^15보다 큰 경우, 즉 오버플로 수가 32768을 초과하는 경우입니다.

    Equal 확장/재배열

참고: 오버플로 버킷 생성은 확장 메커니즘에 속하지 않습니다.

증분 확장

  • 로드 팩터가 너무 크면 새 버킷 공간이 열리고 버킷 수는 이전 2번입니다
  • 새 공간은 버킷으로 참조되고, 이전 공간은 oldbuckets로 참조됩니다
  • 이후 oldbuckets의 데이터는 새로 열린 버킷 공간으로 점진적으로 이동됩니다
지도에 키-값이 수억 개 저장되어 있는 경우 일회성 재배치는 상대적으로 큰 지연을 초래한다는 점을 고려하면 Go는 점진적인 재배치 전략을 채택합니다. 즉,

지도에 액세스할 때마다 재배치를 트리거합니다. 2개의 키-값 쌍이 재배치되었습니다 . oldbuckets의 모든 키-값 쌍이 재배치된 후 oldbuckets를 삭제하세요.

다음 그림은 완전히 로드된 버킷이 포함된 맵을 보여줍니다(설명의 편의를 위해 그림에서 버킷의 값 영역은 생략됨).

현재 맵은 7개의 키-값 쌍을 저장합니다. 버킷은 1개뿐입니다. 이때 부하율은 7> 데이터가 다시 삽입되면

expansion 작업이 트리거됩니다. expansion 후에 새 삽입 키가 새 버킷에 기록됩니다. 로드 팩터가 트리거되므로 오버플로 버킷이 생성되지 않습니다.

8번째 키-값 쌍이 삽입되면

expansion이 트리거됩니다. expansion 이후의 회로도는 다음과 같습니다.

맵에 대한 후속 액세스 작업은 마이그레이션을 트리거하고 oldbucket의 키-값 쌍을 점진적으로 재배치하는 것입니다.

마이그레이션이 완료된 후의 다이어그램은 다음과 같습니다.

데이터 마이그레이션 과정에서 원래 버킷의 키-값 쌍은 새 버킷 앞에 존재하게 되며 새로 삽입된 키-값 쌍은 새 버킷의 뒷면에 존재하게 됩니다.

동일 확장/재배열

이른바 동일

확장은 실제로 용량 확장을 의미하지 않습니다. 증분 확장과 유사한 재배치 작업을 다시 수행하고 제거해야 합니다. 느슨한 키는 버킷이 더 효율적으로 사용되도록 값 쌍이 재배열되어 더 빠른 액세스가 보장됩니다. 지속적인 추가 및 삭제, 키-값 쌍이 소수의 버킷에 집중되는 등의 극단적인 시나리오에서는 오버플로 버킷 수가 증가하지만 부하율이 높지 않아 수행이 불가능합니다. 증분 재배치는 다음과 같습니다. 그림에 표시된 대로:

위 그림에서 볼 수 있듯이 대부분의 오버플로 버킷이 비어 있으며 액세스 효율성이 매우 낮습니다. 이때 균등 확장이 수행됩니다. 즉, 버킷 수는 변경되지 않습니다. 재구성 후에는 오버플로 버킷 수가 줄어들어 공간이 절약되고 액세스 효율성이 향상됩니다.

【관련 추천: Go 비디오 튜토리얼

,

프로그래밍 교육

위 내용은 Go 언어의 확장 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.