Получить указатели для значений в срезе - PullRequest
0 голосов
/ 16 января 2019

Есть ли способ получить указатели на фактическое значение в срезе? У меня есть дерево предложений на картах:

map[uint64]map[uint16][]offer

Для быстрого доступа по id (который от 1 до n) мне нужен кусок указателей:

[]*offer

Фактические предложения лежат в первом дереве, в срезе должны быть указатели на то, что актуально.

Я не могу пройти по дереву и собрать указатели фактических значений, потому что с range этого среза я получаю копии, но у меня есть более миллиардов этих структур в целом, и копии приведут к потере моей памяти: 40 байты для одной структуры приводят к 100+ ГБ и намного больше в будущем. Мне также нужно хранить срез значений в дереве, чтобы они были непрерывными для фактического поиска предложений.

Может быть, есть какой-нибудь способ использовать пакет unsafe или reflect для получения этих указателей?

Индекс указателей создается только один раз, и обе структуры являются неизменяемыми и используются только для поиска предложений.

Обновление: Я был совершенно неправ. Нет проблем получить указатель на элемент в срезе. Мой код был:

        var offers []offer // actually there was about 50gb of offers
        for i := range offers {
            currentOffer := offers[i]
            s.Relations[currentOffer.Id] = &currentOffer
        }

После этого фрагмента общее количество оперативной памяти, потребляемой приложением, составило 100 + ГБ. Я сразу подумал, что взять элемент из среза значений даст мне копию этого значения, но это неправильно. Я просто скопировал исходное значение в переменную currentOffer самостоятельно. Маленькая ошибка убрала 50 ГБ ОЗУ.

На самом деле этот фрагмент работает нормально, как и ожидалось:

    for i := range offers {
        s.Relations[offers[i].Id] = &offers[i]
    }

1 Ответ

0 голосов
/ 16 января 2019

После некоторого расследования я пришел к следующему коду:

package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

type offer struct {
    id uint64
}

func main() {

    sl := []offer{{1}, {id: 2}}

    size := unsafe.Sizeof(offer{})
    header := (*reflect.SliceHeader)(unsafe.Pointer(&sl))
    for i := 0; i < len(sl); i++ {
        offset := uintptr(i) * size
        ptr := header.Data + offset

        o := (*offer)(unsafe.Pointer(ptr))
        o.id = 5
        fmt.Println(o)
    }

    for _, o := range sl {
        fmt.Println(o.id)
    }
}

Детская площадка: https://play.golang.org/p/OM3i84cKAB_7

Выход:

&{5}
&{5}
5
5

Этот фрагмент кода иллюстрирует доступ к фактическим данным в срезе, а не к скопированным.

Обновление: Взятие указателей через небезопасный указатель дает тот же эффект, что и получение обычного указателя из среза по индексу.

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