gpt4 book ai didi

使用 scalaz-stream 的行计数性能

转载 作者:行者123 更新时间:2023-12-04 03:23:15 27 4
gpt4 key购买 nike

我翻译了 Functional Programming in Scala 第 15 章开头的命令式行计数代码(参见 linesGt1)到使用 scalaz-stream 的解决方案(参见 linesGt2)。然而,linesGt2 的性能并不是很好。命令式代码比我的 scalaz-stream 解决方案快大约 30 倍。所以我想我做的事情从根本上是错误的。如何提高 scalaz-stream 代码的性能?

这是我完整的测试代码:

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
}

最佳答案

当您进行性能分析或计时时,您可以使用 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 微秒(例如,尝试 Process.range(0,10000)。如果您有具有多个阶段的管道,那么整个流的每个步骤都将包含其他几个步骤。考虑最小化 scalaz-stream 开销的方法只是确保您在每个步骤中都做了足够的工作以使任何步骤相形见绌由 scalaz-stream 本身添加的开销。This post has more details on this approach。行计数示例是一种最坏的情况,因为您几乎没有在每个步骤中执行任何操作,而只是计算步骤。

所以我会尝试编写一个每步读取多行的 linesR 版本,并确保在 JIT 之后进行测量。

关于使用 scalaz-stream 的行计数性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18853079/

27 4 0