эффективный способ памяти - PullRequest
0 голосов
/ 14 марта 2019

У меня есть два примера аналогичной программы, написанной на Go. Основной целью этого кода является сортировка карты структур по значению в структуре.

Пример с указателями

package main

import (
    "fmt"
    "sort"
)

type payload struct {
    data string
    value  float64
}

type container struct {
    counter int
    storage map[int]*payload
}

type payloadSlice []*payload

// Len is part of sort.Interface.
func (p payloadSlice) Len() int {
    return len(p)
}

// Swap is part of sort.Interface.
func (p payloadSlice) Swap(i, j int) {
    p[i], p[j] = p[j], p[i]
}

// Less is part of sort.Interface. We use count as the value to sort by
func (p payloadSlice) Less(i, j int) bool {
    return p[i].value < p[j].value
}
func main() {
    name := "special_unique_name"
    var m = map[string]container{
        name: {counter: 10, storage: map[int]*payload{
            5: {data: "epsilon", value: 55},8: {data: "theta", value: 85},4: {data: "delta", value: 48},1: {data: "alpha", value: 14},10: {data: "kappa", value: 101},
            3: {data: "gamma", value: 31},6: {data: "zeta", value: 63},2: {data: "beta", value: 26},9: {data: "iota", value: 92},7: {data: "eta", value: 79},
        }},
    }
    s := make(payloadSlice, 0, len(m[name].storage))
    for _, v := range m[name].storage {
        s = append(s, v)
    }
    sort.Sort(s)

    for _, v := range s {
        fmt.Println(name, v)
    }
}

Примеры со значениями

package main

import (
    "fmt"
    "sort"
)

type payload struct {
    data string
    value  float64
}

type container struct {
    counter int
    storage map[int]payload
}

type payloadSlice []payload

// Len is part of sort.Interface.
func (p payloadSlice) Len() int {
    return len(p)
}

// Swap is part of sort.Interface.
func (p payloadSlice) Swap(i, j int) {
    p[i], p[j] = p[j], p[i]
}

// Less is part of sort.Interface. We use count as the value to sort by
func (p payloadSlice) Less(i, j int) bool {
    return p[i].value < p[j].value
}
func main() {
    name := "special_unique_name"
    var m = map[string]container{
        name: {counter: 10, storage: map[int]payload{
            5: {data: "epsilon", value: 55},8: {data: "theta", value: 85},4: {data: "delta", value: 48},1: {data: "alpha", value: 14},10: {data: "kappa", value: 101},
            3: {data: "gamma", value: 31},6: {data: "zeta", value: 63},2: {data: "beta", value: 26},9: {data: "iota", value: 92},7: {data: "eta", value: 79},
        }},
    }
    s := make(payloadSlice, 0, len(m[name].storage))
    for _, v := range m[name].storage {
        s = append(s, v)
    }
    sort.Sort(s)

    for _, v := range s {
        fmt.Println(name, v)
    }
}

Я бы хотел знать 2 момента:

  1. Какой пример будет эффективным для памяти? (Я полагаю, это путь указателя)

  2. Как измерить производительность этих примеров, используя данные испытаний с разным количеством структур внутри карты? Можете ли вы помочь мне с созданием Benchmark?

Полагаю, размер каждой структуры на карте будет варьироваться в среднем от 1-2 КБ.

1 Ответ

3 голосов
/ 14 марта 2019

«Эффективное использование памяти» - довольно широкий термин, и может означать несколько очень разных вещей в языке с мусором, например Go, с отдельной кучей и стеком:

  • Что используетнаименьшее количество памяти?
  • Что создает наименьшее давление ГХ?

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

Если вы хотите минимизировать давление GC, вы , вероятно, хотите использовать только указателикогда вам нужна семантика указателя, или базовые значения достаточно велики.Указатель переносит значение в кучу, которая подлежит сборке мусора, в то время как значение может храниться в стеке, чего нет (когда функция возвращается, стек полностью уничтожается, что является поточно-ориентированным и требуетнет отслеживания ссылок).

«Давление ГХ» - это идея о том, что чем больше вещей создается и уничтожается в куче, тем больше работы выполняет сборщик мусора, что отнимает процессорное время от реальной работы вашегоприложение делает.Каждый раз, когда вы выделяете в куче, если нет места для нового значения, сборщик мусора будет пытаться освободить пространство, ища значения в куче, которые больше не нужны.Чем больше вы выделяете в куче, тем чаще GC должен запускаться, и чем дольше будут выполняться эти прогоны.

На ваш второй вопрос вы можете (и должны!) Измерить производительность различных подходов к вашему конкретномуобстоятельства, использующие средство сравнения testing пакета .Убедитесь, что вы тестируете с реалистичными данными и операциями;микробенчмарки или эталоны с использованием «фиктивных» типов данных вряд ли дадут данные какого-либо значения.Документация по этому пакету и бесчисленные публикации в блогах и учебные пособия, которые можно легко найти с помощью веб-поиска, должны помочь вам в правильном направлении написания и использования тестов в Go.

В вашем конкретном случае имейте в виду, чтоваш тип данных - насколько этот вопрос касается - меньше, чем вы думаете: 24 байта в 64-битной системе, независимо от длины строки .Зачем?Поскольку string, внутренне, является структурой, содержащей int для длины и указатель на нижележащие байты.Когда вы пытаетесь оптимизировать использование памяти, помните, что строки, фрагменты (но не массивы!) И карты - это очень маленькие структуры, содержащие указатели на их базовые данные.

И самое главное : преждевременная оптимизация - корень всех зол .Вы должны писать код для двух вещей: функциональность и удобочитаемость.Используйте семантику указателей, когда они предоставляют необходимую вам функциональность, и имеют интуитивно понятный смысл в использовании.Если вы измеряете проблему ресурса (ЦП или память), , тогда вам следует профилировать приложение, чтобы найти источники проблемы, расставить приоритеты и оптимизировать их.

Пока вы не измерили и не профилировали проблему с производительностью, у вас не было проблемы с производительностью.

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