3

関数型プログラミング in ScalalinesGt1の第 15 章の冒頭にある命令型の行カウント コード (「参考文献」を参照) を、 scalaz-stream (「参考文献」を参照)を使用するソリューションに翻訳しました。ただし、パフォーマンスはそれほど優れていません。命令型コードは、私の scalaz-stream ソリューションよりも約 30 倍高速です。だから私は根本的に間違ったことをしていると思います。scalaz-stream コードのパフォーマンスをどのように改善できますか?linesGt2linesGt2

ここに私の完全なテストコードがあります:

import scalaz.concurrent.Task
import scalaz.stream._

object Test06 {

val minLines = 400000

def linesGt1(filename: String): Boolean = {
  val src = scala.io.Source.fromFile(filename)
  try {
    var count = 0
    val lines: Iterator[String] = src.getLines
    while (count <= minLines && lines.hasNext) {
      lines.next
      count += 1
    }
    count > minLines
  }
  finally src.close
}

def linesGt2(filename: String): Boolean =
  scalaz.stream.io.linesR(filename)
    .drop(minLines)
    .once
    .as(true)
    .runLastOr(false)
    .run

def time[R](block: => R): R = {
  val t0 = System.nanoTime()
  val result = block
  val t1 = System.nanoTime()
  println("Elapsed time: " + (t1 - t0) / 1e9 + "s")
  result
}

time(linesGt1("/home/frank/test.txt"))        //> Elapsed time: 0.153122057s
                                              //| res0: Boolean = true
time(linesGt2("/home/frank/test.txt"))        //> Elapsed time: 4.738644606s
                                              //| res1: Boolean = true
}
4

1 に答える 1

2

プロファイリングまたはタイミングを行っている場合、 を使用Process.rangeして入力を生成し、実際の計算を I/O から分離できます。あなたの例を適応させる:

time { Process.range(0,100000).drop(40000).once.as(true).runLastOr(false).run }

これを最初に実行したとき、私のマシンでは約 2.2 秒かかりました。これは、表示されているものと一致しているようです。数回実行した後、おそらく JIT を行った後、一貫して約 0.64 秒を取得していました。原則として、I/O を使用しても同じくらい速くならない理由はわかりません (以下の説明を参照)。 .

私の非公式なテストでは、scalaz-stream の「ステップ」あたりのオーバーヘッドは約 1 ~ 2 マイクロ秒のようです (たとえば、 try Process.range(0,10000)。複数のステージを持つパイプラインがある場合、ストリーム全体の各ステップは他のいくつかのステップで構成されます)。ステップ. scalaz-stream のオーバーヘッドを最小限に抑えることについて考える方法は, scalaz-stream 自体によって追加されるオーバーヘッドを小さくするために, 各ステップで十分な作業を行っていることを確認することです.この投稿には, このアプローチの詳細があります.行カウントの例は、ステップごとにほとんど作業を行っておらず、ステップをカウントしているだけなので、最悪のケースです。

したがってlinesR、ステップごとに複数行を読み取るバージョンを作成してみます。また、JIT 後に測定を行うようにしてください。

于 2013-09-18T14:26:25.550 に答える