gpt4 book ai didi

java - Scala Source.fromFile 内存消耗

转载 作者:行者123 更新时间:2023-12-01 16:52:44 24 4
gpt4 key购买 nike

全部,

我有一个只有 ~120MB 的 CSV 文件(将其命名为 demo.csv)

以下代码会导致堆从正常大小的 100MB 膨胀到 1.7GB,尽管加载的底层数据只有 120MB

我可以在哪些方面做得更好?

case class Foo(x:String, y: Array[String])
....
val src = Source.fromFile(file)
val lines = src.getLines()
val raw = lines.map(_.split(",")).toArray
src.close()

/**
* a map from accountId to their benchmark components
*/
val result = raw.groupBy(_.(0)).map {
case (x, y) => Foo(x,y)
}.toArray

我知道 toArray 可能是这里的问题,但是我确实需要 groupBy ...并且除非我将所有内容都拉入内存,否则无法访问它。有什么替代方案吗?

据我了解,在 groupBytoArray 阶段,堆可能会暂时膨胀。但由于底层数据只有 120MB,我的堆怎么可能永久增加 >1G 呢? (换句话说,无论保留什么,似乎都没有经过 GC)

最佳答案

首先,我建议使用专用的 CSV 解析库 - 手动解析 CSV 比看起来复杂得多,有很多边缘情况(比如说,如果您的某个值包含换行符怎么办? )。我们将选择 kantan.csv因为我是作者,但那里有很多高质量的库。

我们要做的是:

  • 迭代器[(String, String)] 方式打开文件
  • 折叠该迭代器,构建一个 Map[String, List[String]] - 其中键是帐户 ID,值是基准数据。
  • 如果您确实对 Foo 案例类感兴趣,请将 map 转换为该类的列表。

言归正传:

import kantan.csv._     // kantan.csv core types.
import kantan.csv.ops._ // syntax.

case class Foo(id: String, data: List[String])

// Open the CSV file for reading, assuming ; as column separator
// and no header row.
input.asUnsafeCsvReader[(String, String)](';', false)

// Fold on the file, aggregating data in a map
.foldLeft(Map.empty[String, List[String]]) { case (acc, (key, value)) =>
acc + (key -> (value :: acc.getOrElse(key, List.empty)))

// Now that we have the whole data as a Map, turn that into a List[Foo].
}.map(r => Foo(r._1, r._2))

这永远不会多次加载输入数据,一旦将其放入聚合映射中,就会丢弃每一行 - 与您的实现相反,如果我没数错的话,到最后它会在内存中存储 4 次(一次为行,一次作为分割线,一次作为 List[Foo] 一次作为 Array[Foo])。

此外,当您别无选择时,字符串是很好的选择,但如果您有更好的类型(例如整数或日期),请改用它们。 int 使用的内存比其字符串表示形式要少得多。

让我知道结果如何!

关于java - Scala Source.fromFile 内存消耗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36703349/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com