Scala快速读取文本文件并上传到内存

12

在Scala中,读取文本文件并将其上传到数组中的常见方法是

scala.io.Source.fromFile("file.txt").getLines.toArray

特别是对于非常大的文件,也许有一种更快的方法,先将字节块读入内存,然后通过换行符进行分割?(有关常用方法,请参见在Scala中读取整个文件。)

非常感谢。


2
请注意,Source 使用 BufferedSource,而 BufferedSource 又使用了 Java 的 BufferedReader。因此,它已经将数据块读入内存 - 而不是逐字节读取。 - DNA
1
请定义“非常大的文件”以及在将其分成行之后要对这些数据做什么。 - om-nom-nom
@om-nom-nom 数值数组 20,000 x 500 ~ 200MB - elm
1
接下来,显而易见的问题是:您当前的方法有多快,而足够快需要多快? - Patryk Ćwiek
fromFile()有一个重载形式,它接受一个缓冲区大小参数。你尝试增加过这个参数吗?建议大于2048。 - n0741337
显示剩余5条评论
1个回答

21

性能问题与读数据的方式无关,数据已经被缓存。只有在实际迭代行时才会发生任何事情:

// measures time taken by enclosed code
def timed[A](block: => A) = {
  val t0 = System.currentTimeMillis
  val result = block
  println("took " + (System.currentTimeMillis - t0) + "ms")
  result
}

val source = timed(scala.io.Source.fromFile("test.txt")) // 200mb, 500 lines
// took 0ms

val lines = timed(source.getLines)
// took 0ms

timed(lines.next) // read first line
// took 1ms

// ... reset source ...

var x = 0
timed(lines.foreach(ln => x += ln.length)) // "use" every line
// took 421ms

// ... reset source ...

timed(lines.toArray)
// took 915ms

考虑我的硬盘的读取速度每秒为500mb,对于200mb的数据,最佳时间是400ms,这意味着除了不将迭代器转换为数组外,没有其他改进的余地。

根据你的应用程序,你可以考虑直接使用迭代器而不是数组。因为在内存中处理如此巨大的数组肯定会成为性能问题。


编辑:从你的评论中我猜测你想进一步转换该数组(例如将行分割成列,正如你所说你正在读取一个数字数组)。在这种情况下,我建议在读取时进行转换。例如:

source.getLines.map(_.split(",").map(_.trim.toInt)).toArray

比...快很多。

source.getLines.toArray.map(_.split(",").map(_.trim.toInt))

对我来说,它只需要1.9秒而不是2.5秒,因为你并没有将整个巨大的数组转换成另一个数组,而是仅仅单独地处理每一行,最终得到一个单一的数组(使用了一半的堆空间)。此外,由于读取文件是一个瓶颈,边读取边转换的好处是可以更好地利用CPU。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接