내 연락처 정보
우편메소피아@프로톤메일.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
목차
2. Go 언어에서 값 전송, 주소 전송(참조 전송)을 어떻게 사용하나요? 차이점이 뭐야?
3. Go 언어에서 배열과 슬라이스의 차이점은 무엇입니까? Go 언어로 전달할 때 배열과 슬라이스의 차이점은 무엇입니까? Go 언어는 슬라이스 확장을 어떻게 구현합니까?
4.고컨베이(Go Convey)란 무엇인가요? 일반적으로 어떤 용도로 사용되나요?
6. Go 슬라이스의 기본 구현은 무엇입니까? 슬라이스 확장 메커니즘을 사용하시겠습니까?
8. 슬라이스가 스레드로부터 안전하지 않은 이유는 무엇입니까?
차이점: 1. Make는 Slice, Map 및 chan 유형의 데이터를 할당하고 초기화하는 데만 사용할 수 있는 반면 new는 모든 유형의 데이터를 할당할 수 있습니다.
2. 새 할당은 "*Type" 유형인 포인터를 반환하고 make는 유형인 참조를 반환합니다.
3. new에 의해 할당된 공간은 지워집니다. make가 공간을 할당한 후에는 초기화됩니다.
값을 전달하면 매개변수의 값만 복사하여 해당 함수에 넣습니다. 두 변수의 주소는 서로 다르며 서로 수정할 수 없습니다.
주소 전달(참조 전달)은 변수 자체를 해당 함수에 전달하며 변수의 값 내용은 함수에서 수정할 수 있습니다.
정렬:
배열 고정 길이 배열 길이는 배열 유형의 일부이므로 [3]int와 [4]int는 두 가지 다른 배열 유형입니다. 지정하지 않으면 크기가 자동으로 계산됩니다. 초기화 쌍은 값으로 전달될 수 없습니다.
일부분:
슬라이스의 길이는 변경될 수 있습니다. 슬라이스는 포인터, 길이, 용량의 세 가지 속성으로 크기를 지정할 필요가 없습니다. 슬라이스는 주소로 전달되고(참조로 전달) 배열이나 내장 함수 make()를 통해 초기화될 수 있습니다. 그런 다음 초기화 중에 len=cap이 확장됩니다.
배열은 값 유형이고 슬라이스는 참조 유형입니다.
배열의 길이는 고정되어 있지만 슬라이스는 그렇지 않습니다. (슬라이스는 동적 배열입니다.)
슬라이스의 기본 레이어는 배열입니다.
Go 언어의 슬라이스 확장 메커니즘은 기본 배열을 재할당하고 데이터를 새 배열로 마이그레이션하여 확장을 달성합니다. 특히, 슬라이스를 확장해야 할 때 Go 언어는 새로운 기본 배열을 생성하고 원래 배열의 데이터를 새 배열에 복사합니다. 그런 다음 슬라이스 포인터가 새 배열을 가리키고, 길이는 원래 길이에 확장된 길이를 더한 값으로 업데이트되고, 용량은 새 배열의 길이로 업데이트됩니다.
슬라이스 확장을 달성하려면 다음을 수행하십시오.
가1.17
- // src/runtime/slice.go
-
- func growslice(et *_type, old slice, cap int) slice {
- // ...
-
- newcap := old.cap
- doublecap := newcap + newcap
- if cap > doublecap {
- newcap = cap
- } else {
- if old.cap < 1024 {
- newcap = doublecap
- } else {
- // Check 0 < newcap to detect overflow
- // and prevent an infinite loop.
- for 0 < newcap && newcap < cap {
- newcap += newcap / 4
- }
- // Set newcap to the requested cap when
- // the newcap calculation overflowed.
- if newcap <= 0 {
- newcap = cap
- }
- }
- }
-
- // ...
-
- return slice{p, old.len, newcap}
- }
메모리 공간을 할당하기 전에 런타임 시 슬라이스의 현재 용량을 기반으로 다양한 확장 전략을 선택할 수 있습니다.
예상 용량이 현재 용량의 두 배보다 크면 예상 용량이 사용됩니다. 현재 조각의 길이가 1024보다 작으면 현재 조각의 길이가 다음보다 크거나 같으면 용량이 두 배가 됩니다. 1024, 새로운 용량이 예상 용량보다 클 때까지 용량은 매번 25%씩 증가합니다.
가1.18
- // src/runtime/slice.go
-
- func growslice(et *_type, old slice, cap int) slice {
- // ...
-
- newcap := old.cap
- doublecap := newcap + newcap
- if cap > doublecap {
- newcap = cap
- } else {
- const threshold = 256
- if old.cap < threshold {
- newcap = doublecap
- } else {
- // Check 0 < newcap to detect overflow
- // and prevent an infinite loop.
- for 0 < newcap && newcap < cap {
- // Transition from growing 2x for small slices
- // to growing 1.25x for large slices. This formula
- // gives a smooth-ish transition between the two.
- newcap += (newcap + 3*threshold) / 4
- }
- // Set newcap to the requested cap when
- // the newcap calculation overflowed.
- if newcap <= 0 {
- newcap = cap
- }
- }
- }
-
- // ...
-
- return slice{p, old.len, newcap}
- }
-
이전 버전과의 차이점은 주로 확장 임계값과 다음 코드 줄에 있습니다.newcap += (newcap + 3*threshold) / 4
。
메모리 공간을 할당하기 전에 런타임 시 슬라이스의 현재 용량을 기반으로 다양한 확장 전략을 선택할 수 있습니다.
예상 용량이 현재 용량의 두 배보다 큰 경우 예상 용량이 사용됩니다.
현재 조각의 길이가 임계값(기본값 256)보다 작으면 용량이 두 배가 됩니다.
현재 슬라이스의 길이가 임계값(기본값 256)보다 크거나 같으면 용량은 매번 25%씩 증가합니다. 벤치마크는 다음과 같습니다. newcap + 3*threshold
, 새로운 용량이 예상 용량보다 커질 때까지;
슬라이스 확장은 go1.18 이전과 이후의 두 단계로 나뉩니다.
1. go1.18 이전:
예상 용량이 현재 용량의 두 배보다 큰 경우 예상 용량이 사용됩니다.
현재 슬라이스의 길이가 1024보다 작으면 용량은 두 배가 됩니다.
현재 슬라이스의 길이가 1024보다 큰 경우 새 용량이 예상 용량보다 커질 때까지 용량은 매번 25%씩 증가합니다.
2. go1.18 이후:
예상 용량이 현재 용량의 두 배보다 큰 경우 예상 용량이 사용됩니다.
현재 조각의 길이가 임계값(기본값 256)보다 작으면 용량이 두 배가 됩니다.
현재 슬라이스의 길이가 임계값(기본값 256)보다 크거나 같으면 용량은 매번 25%씩 증가합니다. 벤치마크는 다음과 같습니다. newcap + 3*threshold
, 새로운 용량이 예상 용량보다 커질 때까지;
go Convey는 golang을 지원하는 단위 테스트 프레임워크입니다.
go Convey는 파일 수정 사항을 자동으로 모니터링하고 테스트를 시작할 수 있으며, 테스트 결과를 실시간으로 웹 인터페이스에 출력할 수 있습니다.
go Convey는 테스트 케이스 작성을 단순화하기 위한 풍부한 주장을 제공합니다.
연기의 기능은 다음과 같습니다.
defer에 필요한 구문을 완성하려면 일반 함수나 메서드를 호출하기 전에 defer 키워드만 추가하면 됩니다. defer 문이 실행되면 defer 뒤의 함수가 연기됩니다. defer 문이 포함된 함수가 return을 통해 정상적으로 종료되거나 패닉으로 인해 비정상적으로 종료되더라도 defer 문이 포함된 함수가 실행될 때까지 defer 이후의 함수는 실행되지 않습니다. 선언의 역순으로 함수에서 여러 defer 문을 실행할 수 있습니다.
연기에 대한 일반적인 시나리오:
defer 문은 열기, 닫기, 연결, 연결 끊기, 잠금 및 잠금 해제와 같은 쌍 작업을 처리하는 데 자주 사용됩니다.
연기 메커니즘을 통해 함수 논리가 아무리 복잡하더라도 모든 실행 경로에서 리소스가 해제되도록 보장할 수 있습니다.
슬라이싱은 배열을 기반으로 구현됩니다. 기본 레이어는 배열 자체로 매우 작으며 기본 배열의 추상화로 이해될 수 있습니다. 배열 기반으로 구현되므로 기본 메모리가 지속적으로 할당되므로 매우 효율적이며, 인덱스를 통해서도 데이터를 얻을 수 있고 반복 및 가비지 수집 최적화가 가능합니다. 슬라이스 자체는 동적 배열이나 배열 포인터가 아닙니다. 내부적으로 구현된 데이터 구조는 포인터를 통해 기본 배열을 참조하며, 해당 속성은 데이터 읽기 및 쓰기 작업을 지정된 영역으로 제한하도록 설정됩니다. 슬라이스 자체는 읽기 전용 개체이며 작동 메커니즘은 배열 포인터의 캡슐화와 유사합니다.
슬라이스 객체는 3개의 필드만 있는 데이터 구조이기 때문에 매우 작습니다.
기본 배열에 대한 포인터
슬라이스 길이
슬라이스 용량
Go(1.17)의 슬라이싱 확장 전략은 다음과 같습니다.
첫 번째 판단으로, 새로 적용되는 용량이 기존 용량의 2배보다 클 경우 최종 용량은 새로 적용되는 용량이 됩니다.
그렇지 않고 이전 슬라이스의 길이가 1024보다 작으면 최종 용량은 이전 용량의 두 배가 됩니다.
그렇지 않고 이전 슬라이스 길이가 1024보다 크거나 같으면 최종 용량이 새로 요청된 용량 이상이 될 때까지 최종 용량이 이전 용량의 1/4씩 주기적으로 증가합니다.
최종 용량 계산 값이 오버플로되면 최종 용량은 새로 요청된 용량입니다.
상황 1:
원래 배열에는 여전히 확장할 수 있는 용량이 있습니다(실제 용량은 채워지지 않았습니다). 이 경우 확장된 배열은 여전히 원래 배열을 가리킵니다. 슬라이스의 작업은 동일한 주소를 가리키는 여러 포인터에 영향을 줄 수 있습니다. 일부분.
상황 2:
배열의 용량이 최대값에 도달한 것으로 나타났습니다. 용량을 확장하려는 경우 Go는 기본적으로 먼저 메모리 영역을 열고 원래 값을 복사한 다음 추가() 작업을 수행합니다. 이 상황은 원래 배열에 전혀 영향을 미치지 않습니다. 슬라이스를 복사하려면 복사 기능을 사용하는 것이 가장 좋습니다.
slice底层结构并没有使用加锁等方式,不支持并发读写,所以并不是线程安全的, 使用多个 goroutine 对类型为 slice 的变量进行操作,每次输出的值大概率都不会一样,与预期值不一致; slice在并发执行中不会报错,但是数据会丢失 如果想实现slice线程安全,有两种方式: 方式一:通过加锁实现slice线程安全,适合对性能要求不高的场景。
- func TestSliceConcurrencySafeByMutex(t *testing.T) {
- var lock sync.Mutex //互斥锁
- a := make([]int, 0)
- var wg sync.WaitGroup
- for i := 0; i < 10000; i++ {
- wg.Add(1)
- go func(i int) {
- defer wg.Done()
- lock.Lock()
- defer lock.Unlock()
- a = append(a, i)
- }(i)
- }
- wg.Wait()
- t.Log(len(a))
- // equal 10000
- }
-
方式二:通过channel实现slice线程安全,适合对性能要求高的场景。
- func TestSliceConcurrencySafeByChanel(t *testing.T) {
- buffer := make(chan int)
- a := make([]int, 0)
- // 消费者
- go func() {
- for v := range buffer {
- a = append(a, v)
- }
- }()
- // 生产者
- var wg sync.WaitGroup
- for i := 0; i < 10000; i++ {
- wg.Add(1)
- go func(i int) {
- defer wg.Done()
- buffer <- i
- }(i)
- }
- wg.Wait()
- t.Log(len(a))
- // equal 10000
- }