私はScalaで大きなデータを処理しているので、メモリと時間は通常よりもさらに重要なコンパニオンです。いくつかのサブ評価を並行して行い、結果をマージするために、大きなソースファイルでIterator[String]
取得したイニシャルを細分化することで、いくつかの評価の速度を上げようとしています。getLines
これを行うにはslice
、イテレータを2つに再帰的に分割し、各サブイテレータの再帰関数を呼び出します。ここで、なぜGCoverheadまたはJavaHeapSpace例外が発生するのか疑問に思っていますが、「重要な」要素は(イテレータのサイズを取得するために)再帰ステップの前に1回だけ評価されますが、私の意見では、再帰ステップでは評価されません。slice
イテレータを再度返します(これは実装によって厳密ではありません)。次の(削減された!)コードは、サブリストを連結する前に、〜15gのファイルに適用できません。
.duplicate
各ステップで使用します。APIを調べたところ、.duplicate
「実装は、一方のイテレータによって繰り返された要素に一時ストレージを割り当てる可能性がありますが、もう一方のイテレータによってまだ割り当てられていない可能性があります。」と書かれていますが、要素はまだ繰り返されていません。誰かが私にそこで何が間違っているのか、そしてこの問題を解決する方法のヒントを教えてもらえますか?どうもありがとう!
type itType = Iterator[String]
def src = io.Source.fromFile(args(0)).getLines
// recursively divide into equal size blocks in divide&conquer fashion
def getSubItsDC(it: itType, depth: Int = 4) = {
println("Getting length of file..")
val totalSize = src.length
println(totalSize)
def rec(it_rec: itType = it, depth_rec: Int = depth, size: Int = totalSize):
List[itType] = depth_rec match {
case n if n > 0 =>
println(n)
val (it1, it2) = it_rec.duplicate
val newSize = size/2
rec(it1 slice (0,newSize), n-1, newSize) ++
rec(it2 slice (newSize,size), n-1, newSize)
case n if n == 0 => List(it_rec)
}
println("Starting recursion..")
rec()
}
getSubItsDC(src)
REPLでは、コードは任意のサイズのイテレーターで同じように高速に実行されるため(totalSizeをハードコーディングする場合)、正しい怠惰であると想定しました。