Почему именно параметр CAPACITY при создании среза в Golang? - PullRequest
0 голосов
/ 20 февраля 2019

Это довольно простой вопрос:

Если емкость среза в Голанге может быть превышена, почему параметр емкости вообще стоит на первом месте?

Я считаю, что это связано с управлением памятью , своего рода "знанием, где разместить фрагмент в памяти", но я точно не знаю.

Ответы [ 3 ]

0 голосов
/ 20 февраля 2019

Чтобы увеличить емкость среза, необходимо создать новый, больший срез и скопировать в него содержимое исходного среза.

Если емкость срезав Golang может быть превышен, почему параметр емкости на первом месте?

Предположим, что мы заранее знаем емкость среза, тогда мы можем использовать параметр емкости встроенной функции make для выделенияпамяти вместо динамического увеличения емкости слайса с использованием команды append, которая неэффективна для этой памяти.

, поэтому в следующем примере

type Element struct {
    Number int
}

func main() {
    Max := 100000
    startTime := time.Now()

    // Capacity given
    elements1 := make([]Element, Max, Max)
    for i := 0; i < Max; i++ {
        elements1[i].Number = i
    }
    elapsedTime := time.Since(startTime)
    fmt.Println("Total Time Taken with Capacity in first place: ", elapsedTime)

    startTime = time.Now()
    // Capacity not given
    elements2 := make([]Element, 0)
    for i := 0; i < Max; i++ {
        elements2 = append(elements2, Element{Number: i})
    }
    elapsedTime = time.Since(startTime)
    fmt.Println("Total Time Taken without capacity: ", elapsedTime)
}

output

Total Time Taken with Capacity in first place:  121.084µs
Total Time Taken without capacity:  2.720059ms

Время, затраченное на создание слайса с емкостью на первом месте, меньше, чемстроить динамически

Таким образом, чтобы ответить на ваш вопрос, параметр емкости стоит на первом месте для повышения производительности и эффективности памяти

0 голосов
/ 20 февраля 2019

В блоге Голанга много отличных постов.Этот один на слайсах , даст вам детальное представление о базовой реализации слайсов и о том, как работает емкость.

В статье рассказывается, как работает операция append и как значение емкостипозволяет append знать, следует ли повторно использовать базовый массив памяти или выделить больший массив, когда требуется большая емкость.

0 голосов
/ 20 февраля 2019

Если емкость среза в Голанге может быть превышена, почему параметр емкости вообще стоит?

Я не знаю, чтоВы подразумеваете под этим, но емкость не может быть превышена.Срезы могут быть проиндексированы вплоть до его длины (исключая), которая не может превышать емкость, и они могут быть повторно разрезаны до ее емкости (включительно).

Spec: Индексные выражения:

Первичное выражение вида a[x]

Если a не является картой: ... индекс x равен в диапазоне если 0 <= x < len(a), в противном случае выходит за пределы диапазона

и Spec: выражения среза:

... Первичное выражение: a[low : high]

Для массивов или строк индексы находятся в диапазоне в диапазоне , если 0 <= low <= high <= len(a), в противном случае они находятся вне диапазона .Для слайсов верхняя граница индекса - это емкость слайса cap(a), а не длина.

А также:

... основное выражение: a[low : high : max]

Индексы в диапазоне , если 0 <= low <= high <= max <= cap(a), в противном случае они вне диапазона .

Вы можете предоставить емкость длявстроенный make() думает о будущем росте, поэтому потребуется меньше ассигнований, если вам нужно будет добавить элементы к нему или вам нужно будет заменить его.Встроенный append() просто повторяет фрагмент, к которому вы добавляете, если у него достаточно места для дополнительных элементов, но он должен выделить новый резервный массив (и скопировать в него существующее содержимое), если у него неткомната для новых элементов.append() вернет новый фрагмент, который может указывать или не указывать на исходный массив поддержки.

Давайте рассмотрим пример.Давайте создадим срез длиной 0 и емкостью и добавим к нему 10 элементов.И чтобы увидеть, когда происходит новое перераспределение, мы также печатаем адрес его первого элемента (0-й элемент):

fmt.Println("With 0 capacity")
s := make([]int, 0)
for i := 0; i < 10; i++ {
    s = append(s, i)
    fmt.Println(i, &s[0])
}

Это выводит:

With 0 capacity
0 0x416030
1 0x416030
2 0x416040
3 0x416040
4 0x452000
5 0x452000
6 0x452000
7 0x452000
8 0x434080
9 0x434080

Как вы можете видеть,новый резервный массив выделяется, когда мы добавили третий (i=2), пятый (i=4) и девятый элементы (i=8), а также когда мы добавили первый элемент (поскольку исходный резервный массив не мог содержать какой-либоэлементы).

Теперь давайте повторим приведенный выше пример, когда мы создадим начальный срез с длиной length = 0, но с емкостью = 10:

fmt.Println("With 10 capacity")
s = make([]int, 0, 10)
for i := 0; i < 10; i++ {
    s = append(s, i)
    fmt.Println(i, &s[0])
}

Теперь вывод будет:

With 10 capacity
0 0x44c030
1 0x44c030
2 0x44c030
3 0x44c030
4 0x44c030
5 0x44c030
6 0x44c030
7 0x44c030
8 0x44c030
9 0x44c030

Как вы можете видеть, адрес первого элемента никогда не менялся, что означает, что в фоновом режиме не было новых выделений резервного массива.

Попробуйте пример на Go Playground .

...