2016-04-26 2 views
0

Go для меня довольно новый, и у меня есть некоторые проблемы с пониманием использования памяти:Как уменьшить использование памяти в [] строке?

Я хочу загрузить файл, похожий на csv, в массив строк, каждая строка которого представляет собой структуру, состоящую из ключа на 22 символа и массив значений (строка).
Мой код выглядит так: https://play.golang.org/p/hJ4SHjVXaG

Проблема в том, что для файла 450M он использует около 2G1 памяти.
У кого-нибудь есть решение сократить использование этой памяти?

Обновление с помощью SirDarius решение: https://play.golang.org/p/DBmOFOkZdx все еще используют около 1G9

+0

Какую проблему решаете с вашей программой? Методы уменьшения памяти могут быть очень разными и зависят от класса проблемы. – rootatdarkstar

+0

Прочитать файл по строкам. Рецепт находится здесь: http://stackoverflow.com/a/8758113/1975086 –

+1

Вам нужно все в памяти сразу? Не можете ли вы просто обработать файл по очереди, как предложил @AlexanderTrakhimenok? – icza

ответ

6

Сколько строк и полей есть в файле?

Правдоподобно, что то, что вы описываете, использует минимальный объем памяти.

Глядя на код, я думаю, он будет использовать 450 МБ памяти для основных данных строки.

Затем он разрезит это на строки. Они состоят из указателя и длины, которые принимают 16 байтов на 64-битной платформе.

So 1,5GB/16 = 93Million.

Итак, если в вашем файле имеется> 50 миллионов полей, то использование памяти кажется разумным.

Другие накладные расходы, такие как количество строк и т. Д., Поэтому это не точный расчет.

EDIT

Учитывая
5 миллионов строк, 10 колонка каждый

Это 50 миллионов строк заголовков из 16 байт, которые будут принимать 800 Мбайт. Плюс сами данные 450 Мбайт плюс 5 * 8 * 5 миллионов строк = 200 МБ составляют 1,45 ГБ

Поэтому я не думаю, что даже с идеальным распределением памяти вы сможете уменьшить использование ниже 1,5 ГБ.

+1

5 миллионов строк, 10 столбцов каждый – rWick

2

Это кажется довольно неэффективно для меня:

for _, value := range strings.Split(line[23:], ";") { 
    row.Values = append(row.Values, value) 
} 

Вы в основном получить []string, вызвав функцию string.Split, а затем цикл над этим кусочком к добавьте каждую строку в другой изначально нулевой фрагмент строки.

Почему бы не просто сделать:

row.Values = strings.Split(line[23:], ";") 

вместо этого?

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

+0

Действительно, это довольно бесполезно, у меня была проверка действительности в этом цикле, но я могу отложить их. Я только что попробовал, он дошел до 1g9, не идеально, но уже лучше! Благодаря ! – rWick

1

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

Глядя на функцию Split, она возвращает кусочек подстрок, поэтому нет необходимости перемещаться по приведенным фрагментам и добавлять их в row.Values. Вы можете назначить приведенные значения непосредственно на row.Values, а затем добавить их к фрагменту rows.

func Split(s, sep string) []string 

Split ломтики ы во все подстроки, разделенных сна и возвращает кусочка подстрок между этими сепараторами. Если sep пуст, Разделение разделов после каждой последовательности UTF-8. Это эквивалентно SplitN со счетом -1.

row.Values = strings.Split(line[23:], ";") 
rows = append(rows, row) 
0

Кажется мне, это о добавить функцию(). От языка спецификации

Если емкость с недостаточно большой, чтобы вместить дополнительные значения, Append выделяет новый, достаточно большой основной массив

Размер этого недавно выделенного массива может быть достаточным потреблять еще более добавочные. Итак, чтобы выделить именно вы должны slice := make([]Row, 0, WithExpectedCapacity) и назначить slice[n]= вместо append(). Если вы не можете сделать это, по крайней мере, можно попробовать отражение уплотнить

reflect.ValueOf(&slice).Elem().SetCap(len(slice)) 

Некоторые сложно, но вы можете увидеть https://play.golang.org/p/LslkOBCvII это работает.

+0

Я знаю размер файла, который я использую для своего теста, поэтому я попытался вручную установить емкость каждого массива, но без большого результата ... Так что, я думаю, это не будет сильно изменились, так как я не использовал append, но я попробую! – rWick

Смежные вопросы