300M超のテキストファイルを読み込ませてIterator.continuallyで処理すると

Iterator.continuallyの動作がどれぐらい大きいファイルまで耐えられるのか確認したく、以下の様なスクリプトを書いてみた。

import java.io.{FileInputStream, InputStreamReader, BufferedReader}

val br = new BufferedReader(new InputStreamReader(new FileInputStream(args(0)),"UTF-8"))
try{
  val it = Iterator.continually(br.readLine).takeWhile(_ != null)
  println("line count = " + it.foldLeft(0)((c,_) => c+1))
} finally {
  br.close
}


これは動く。itを再利用したいから、it.duplicateをしてみた。

 val it = Iterator.continually(br.readLine).takeWhile(_ != null)
  val (it1, it2) = it.duplicate
  println("line count = " + it1.foldLeft(0)((c,_) => c+1))


これをすると、OutofMemoryでクラッシュする。


では、itをvariableにしてit1をitに戻してはどうか。大方の予測どおり、itcopyはただの参照なので、二回目ではゼロになってしまう。

 val it = Iterator.continually(br.readLine).takeWhile(_ != null)
 var itcopy = it
  println("line count = " + itcopy.foldLeft(0)((c,_) => c+1))
  itcopy = it
  println("line count = " + itcopy.foldLeft(0)((c,_) => c+1))


では、TraversableなBufferにしてはどうか。

  val it = Iterator.continually(br.readLine).takeWhile(_ != null)
  val b = it.toBuffer
  println("line count = " + b.foldLeft(0)((c,_) => c+1))
  println("line count = " + b.foldLeft(0)((c,_) => c+1))


これは、toBufferを呼んだ時点でOutOfMemoryでクラッシュ。toList、toArrayも上手くいかない。


おそらく、HeapSizeを増やして実行すればうまくいくかもしれない。