Если я знаю максимальный размер многих фрагментов tmp, должен ли я устанавливать емкость при их создании? - PullRequest
0 голосов
/ 03 марта 2019

Если мне нужно использовать срезы tmp в функции, и функция будет вызываться много раз, их максимальная емкость не будет превышать 10. Но длина их различна.Например, возможно, 80% из них имеют размер только 1. 10% из них имеют размер 3, а 10% из них имеют размер 10.

Я могу представить пример функции, подобной следующей:

func getDataFromDb(s []string) []string {
    tmpSlice := make([]string, 0, 10)
    for _, v := range s {
        if check(v) {
            tmpSlice = append(tmpSlice, v)
        }
    }
    ......
    return searchDb(tmpSlice)
}

Так что мне делать var tmpSlice []string, tmpSlice := make([]string, 0, 0), tmpSlice := make([]string, 0, 5) или tmpSlice := make([]string, 0, 10)?или какие-либо другие предложения?

Ответы [ 3 ]

0 голосов
/ 03 марта 2019

Быстрее всего будет, если код не размещается в куче.

Создайте переменные, которые размещаются в стеке и не экранируют (передайте переменные по значению, в противном случае они выйдут).

Экранирование вы можете проверить, добавив -gcflags "-m -l" при сборке.

Вот пример, который показывает, что если мы заменим slice массивом и передадим его по значению, это приведет к быстрому коду безраспределение (в куче).

package main

import "testing"

func BenchmarkAllocation(b *testing.B) {
    b.Run("Slice", func(b2 *testing.B) {
        for i := 0; i < b2.N; i++ {
            _ = getDataFromDbSlice([]string{"one", "two"})
        }
    })
    b.Run("Array", func(b2 *testing.B) {
        for i := 0; i < b2.N; i++ {
            _ = getDataFromDbArray([]string{"one", "two"})
        }
    })
}

type DbQuery [10]string
type DbQueryResult [10]string

func getDataFromDbArray(s []string) DbQueryResult {
    q := DbQuery{}
    return processQueryArray(q)
}

func processQueryArray(q DbQuery) DbQueryResult {
    return (DbQueryResult)(q)
}

func getDataFromDbSlice(s []string) []string {
    tmpArray := make([]string, 0, 10)
    return processQuerySlice(tmpArray)
}

func processQuerySlice(q []string) []string {
    return q
}

Запуск теста с benchmem дает следующие результаты:

BenchmarkAllocation/Slice-6             30000000            51.8 ns/op       160 B/op          1 allocs/op
BenchmarkAllocation/Array-6             100000000           15.7 ns/op         0 B/op          0 allocs/op
0 голосов
/ 05 марта 2019

В этом ответе предполагается, что searchDB не сохраняет ссылку на переданный ему фрагмент.Представляется маловероятным, что функция сохраняет ссылку, учитывая имена переменных и функций.

Эти параметры имеют одинаковые характеристики памяти и производительности:

 var tmpSlice []string
 tmpSlice := []string{}
 tmpSlice := make([]string, 0)
 tmpSlice := make([]string, 0, 0)

Ни один из них не выделяет память до первого добавленияоперация.Если это ваши единственные варианты, выберите один из первых двух, потому что их легче читать.

Этот параметр будет иметь наилучшую производительность:

tmpSlice := make([]string, 0, 10)

Это гарантирует, что массив резервных копийдля среза выделяется один раз.При добавлении значений не будет перераспределений резервного массива.

Если аргумент searchDB не экранирован, то в стеке будет сделано одно выделение для резервного массива.Это лучшая из возможных характеристик.Вы можете выяснить, сбрасывается ли аргумент, с помощью опции -gcflags "-m -l".

Принимая во внимание, что getDataFromDb вызывает операцию базы данных, любая разница в производительности между опциями будет в шуме.Более важно написать ясный и простой код, чем оптимизировать его.

Я бы, вероятно, пошел с var tmpSlice []string вместо tmpSlice := make([]string, 0, 10), потому что нет необходимости понимать, откуда взято значение 10 с первым.

0 голосов
/ 03 марта 2019

Я бы сделал

var tmpSlice []string

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

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