Golang 读取 csv 在内存中消耗的空间是磁盘空间的 2 倍以上

我正在使用 Golang 将大量 CSV 文件加载到结构中。结构是


type csvData struct {

    Index   []time.Time

    Columns map[string][]float64

}    

我有一个解析器,它使用:


csv.NewReader(file).ReadAll()

然后我遍历行,并将值转换为它们的类型:time.Time或float64.


问题是这些文件在磁盘上占用 5GB 空间。一旦我将它们加载到内存中,它们就会消耗 12GB!


我使用ioutil.ReadFile(path)并发现这与预期的一样几乎完全是磁盘上的大小。


这是我的解析器的代码,为了便于阅读,省略了错误,如果你能帮助我排除故障:


var inMemoryRepo = make([]csvData, 0)


func LoadCSVIntoMemory(path string) {

    parsedData := csvData{make([]time.Time, 0), make(map[string][]float64)}

    file, _ := os.Open(path)

    reader := csv.NewReader(file)

    columnNames := reader.Read()

    columnData := reader.ReadAll()

    for _, row := range columnData {

        parsedData.Index = append(parsedData.Index, parseTime(row[0])) //parseTime is a simple wrapper for time.Parse

        for i := range row[1:] {                                       //parse non-index numeric columns

            parsedData.Columns[columnNames[i]] = append(parsedData.Columns[columnsNames[i]], parseFloat(columnData[i])) //parseFloat is wrapper for strconv.ParseFloat

        }

    }

    inMemoryRepo = append(inMemoryRepo, parsedData)

}

我尝试通过在函数调用结束时将columnData和设置为零来进行故障排除,但没有任何变化。reader


喵喔喔
浏览 240回答 2
2回答

慕工程0101907

这没有什么令人惊讶的。在您的磁盘上只有 CSV 文本的字符(字节)。当您将它们加载到内存中时,您会从文本中创建数据结构。例如,一个float64值在内存中需要 64 位,即:8 个字节。如果您有输入 text "1",则为 1 个单字节。然而,如果你创建一个float64等于 的值1,那仍然会消耗 8 个字节。此外,strings 存储有一个字符串头 ( reflect.StringHeader),它是 2 个整数值(在 64 位架构上为 16 个字节),并且该头指向实际的字符串数据。有关详细信息,请参阅Golang中的字符串内存使用情况。切片也是类似的数据结构:reflect.SliceHeader. 标头由 3 个整数值组成,即使切片中没有元素,在 64 位架构上也是 24 个字节。在此之上的结构可能具有填充(字段必须与某些值对齐),这再次增加了开销。有关详细信息,请参阅规格:尺寸和对齐保证。Go Maps 是 hashmaps,它也有相当多的开销,有关详细信息,请参阅为什么切片值有时会过时但从不映射值?,对于内存使用情况,请参阅Golang maps 保留多少内存?

白衣非少年

很少将整个文件读入内存是一个好主意。如果你的 csv 是 100GiB 怎么办?如果您的转换不涉及多个记录,也许您可以应用以下算法:open csv_reader (source file)open csv_writer (destination file)for row in csv_reader    transform row    write row into csv_writerclose csv_reader and csv_write
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go