Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
具有函数结构的Scala性能_Scala - Fatal编程技术网

具有函数结构的Scala性能

具有函数结构的Scala性能,scala,Scala,我目前正在评测用Scala编写的应用程序的性能,我想知道是否可以使用函数构造。一方面,我喜欢函数式编程的优雅和简洁,另一方面,我害怕由此产生的性能。我发现了一个特别好的例子 我有一个包含一百万个字符的字符串,我需要对每个数字求和。典型的功能方法如下所示: val sum = value.map(_.asDigit).sum.toString 然而,这种漂亮、简洁、实用的方法需要0.98秒(几乎每秒) 这种功能性方法比命令式方法略不简洁,可能更难阅读,需要0.085秒。它更难阅读,速度仍然慢了4

我目前正在评测用Scala编写的应用程序的性能,我想知道是否可以使用函数构造。一方面,我喜欢函数式编程的优雅和简洁,另一方面,我害怕由此产生的性能。我发现了一个特别好的例子

我有一个包含一百万个字符的字符串,我需要对每个数字求和。典型的功能方法如下所示:

val sum = value.map(_.asDigit).sum.toString
然而,这种漂亮、简洁、实用的方法需要0.98秒(几乎每秒)


这种功能性方法比命令式方法略不简洁,可能更难阅读,需要0.085秒。它更难阅读,速度仍然慢了4倍…

首先:你确定你已经对这两个版本进行了适当的基准测试吗?仅仅使用System.nanoTime之类的工具测量执行时间并不能给出准确的结果。看到JVM性能大师Aleksey Shipilёv的这篇有趣而有见地的文章

下面是一个使用优秀scala基准库的基准:

val value = "1234567890" * 100000
def sumf = value.map(_.asDigit).sum
def sumi = { var sum = 0; for(digit <- value) sum += digit.asDigit; sum }

val th = ichi.bench.Thyme.warmed(verbose = println)
scala> th.pbenchOffWarm("Functional vs. Imperative")(th.Warm(sumf))(th.Warm(sumi))
Benchmark comparison (in 6.654 s): Functional vs. Imperative
Significantly different (p ~= 0)
  Time ratio:    0.36877   95% CI 0.36625 - 0.37129   (n=20)
    First     40.25 ms   95% CI 40.15 ms - 40.34 ms
    Second    14.84 ms   95% CI 14.75 ms - 14.94 ms
res3: Int = 4500000
根据@Odomontois的建议进行更新:请注意,如果您真的想优化它,您必须确保字符串的字符没有装箱。这是一个命令式的版本,看起来不是很好看,但也几乎尽可能快。这是使用spire中的cfor宏,但while循环也可以

def sumi3 = {
  var sum = 0
  cfor(0)(_ < value.length, _ + 1) { i => 
    sum += value(i).asDigit
  }
  sum
}

scala> th.pbenchOffWarm("Imperative vs. optimized Imperative")(th.Warm(sumi))(th.Warm(sumi3))
Benchmark comparison (in 4.401 s): Imperative vs. optimized Imperative
Significantly different (p ~= 0)
  Time ratio:    0.08925   95% CI 0.08880 - 0.08970   (n=20)
    First     15.10 ms   95% CI 15.04 ms - 15.16 ms
    Second    1.348 ms   95% CI 1.344 ms - 1.351 ms
res9: Int = 4500000
def sumi3={
var总和=0
cfor(0)(小于value.length,+1){i=>
总和+=值(i)。作为数字
}
总和
}
scala>th.pbenchOffWarm(“命令式vs.优化命令式”)(th.Warm(sumi))(th.Warm(sumi3))
基准比较(在4.401s中):命令式与优化命令式
显著性差异(p~=0)
时间比率:0.08925 95%CI 0.08880-0.08970(n=20)
前15.10毫秒95%置信区间15.04毫秒-15.16毫秒
第二个1.348毫秒95%置信区间1.344毫秒-1.351毫秒
res9:Int=4500000
过早优化免责声明:


除非您绝对确定a)一段代码是性能瓶颈,b)命令式版本快得多,否则我总是更喜欢可读性最好的版本,而不是最快的版本。Scala 2.12将附带一个将使函数样式的许多开销小得多的函数,因为它可以在许多情况下进行高级优化,如闭包内联。

您使用
map
创建了一个您不需要的中间字符串。您应该能够通过使用
value.view.map(u.asDigit).sum来避免它。您的“命令式”版本不是非常命令式的。它使用scala迭代器。关于性能的替代方案,请参见,这不是我的命令式版本,而是OP中的版本。这里有一个真正尖叫的版本,但与夜晚一样难看:
def sumi2={var i=0;var sum=0;while(i
是的,抱歉错误的指责。但我想说的是“如果在基准测试中也包含
cfor
version,那就太酷了”。因为
cf或宏的扩展基本上是您在注释中写的东西,但不那么难看。
val value = "1234567890" * 100000
def sumf = value.map(_.asDigit).sum
def sumi = { var sum = 0; for(digit <- value) sum += digit.asDigit; sum }

val th = ichi.bench.Thyme.warmed(verbose = println)
scala> th.pbenchOffWarm("Functional vs. Imperative")(th.Warm(sumf))(th.Warm(sumi))
Benchmark comparison (in 6.654 s): Functional vs. Imperative
Significantly different (p ~= 0)
  Time ratio:    0.36877   95% CI 0.36625 - 0.37129   (n=20)
    First     40.25 ms   95% CI 40.15 ms - 40.34 ms
    Second    14.84 ms   95% CI 14.75 ms - 14.94 ms
res3: Int = 4500000
def sumf2 = value.foldLeft(0)(_ + _.asDigit)

scala> th.pbenchOffWarm("Functional2 vs. Imperative")(th.Warm(sumf2))(th.Warm(sumi))
Benchmark comparison (in 3.886 s): Functional2 vs. Imperative
Significantly different (p ~= 0)
  Time ratio:    0.89560   95% CI 0.88823 - 0.90297   (n=20)
    First     16.95 ms   95% CI 16.85 ms - 17.04 ms
    Second    15.18 ms   95% CI 15.08 ms - 15.27 ms
res17: Int = 4500000
def sumi3 = {
  var sum = 0
  cfor(0)(_ < value.length, _ + 1) { i => 
    sum += value(i).asDigit
  }
  sum
}

scala> th.pbenchOffWarm("Imperative vs. optimized Imperative")(th.Warm(sumi))(th.Warm(sumi3))
Benchmark comparison (in 4.401 s): Imperative vs. optimized Imperative
Significantly different (p ~= 0)
  Time ratio:    0.08925   95% CI 0.08880 - 0.08970   (n=20)
    First     15.10 ms   95% CI 15.04 ms - 15.16 ms
    Second    1.348 ms   95% CI 1.344 ms - 1.351 ms
res9: Int = 4500000