Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.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_Performance_Immutability - Fatal编程技术网

Scala 不变性和性能

Scala 不变性和性能,scala,performance,immutability,Scala,Performance,Immutability,我尝试搜索stackoverflow,有许多相关主题,包括 但我仍想澄清我的理解是否正确 看起来规则是这样的 更喜欢不可变val而不是不可变var而不是可变val而不是可变var 特别是可变var上的不可变var 但根据统计,不可变var的性能比可变val差得多 REPL中的简单测试 scala -J-Xmx2g scala> import scala.collection.mutable.{Map => MMap} import scala.collection.mutabl

我尝试搜索stackoverflow,有许多相关主题,包括

但我仍想澄清我的理解是否正确

看起来规则是这样的

更喜欢不可变val而不是不可变var而不是可变val而不是可变var 特别是可变var上的不可变var

但根据统计,不可变var的性能比可变val差得多 REPL中的简单测试

scala -J-Xmx2g

scala> import scala.collection.mutable.{Map => MMap}
import scala.collection.mutable.{Map=>MMap}

scala>

scala> def time[R](block: => R): R = {
     |   val t0 = System.nanoTime()
     |   val result = block    // call-by-name
     |   val t1 = System.nanoTime()
     |   println("Elapsed time: " + (t1 - t0) + "ns")
     |   result
     | }
time: [R](block: => R)R

scala>time {val mut_val = MMap[Int, Int](); for (i <- 1 to 1000000) mut_val += (i -> i)}
Elapsed time: 551073900ns

scala>time {var mut_var = MMap[Int, Int](); for (i <- 1 to 1000000) mut_var += (i -> i)}
Elapsed time: 574174400ns

scala>time {var imut_var = Map[Int, Int](); for (i <- 1 to 1000000) imut_var += (i -> i)}
Elapsed time: 860938800ns

scala>time {val mut_val = MMap[Int, Int](); for (i <- 1 to 2000000) mut_val += (i -> i)}
Elapsed time: 1103283000ns

scala>time {var mut_var = MMap[Int, Int](); for (i <- 1 to 2000000) mut_var += (i -> i)}
Elapsed time: 1166532600ns

scala>time {var imut_var = Map[Int, Int](); for (i <- 1 to 2000000) imut_var += (i -> i)}
Elapsed time: 2926954500ns
scala-J-Xmx2g
scala>导入scala.collection.mutable.{Map=>MMap}
导入scala.collection.mutable.{Map=>MMap}
斯卡拉>
scala>def时间[R](块:=>R):R={
|val t0=System.nanoTime()
|val result=block//按名称调用
|val t1=System.nanoTime()
|println(“经过的时间:”+(t1-t0)+“ns”)
|结果
| }
时间:[R](块:=>R)R
scala>time{val mut_val=MMap[Int,Int]();用于(i)}
运行时间:551073900ns
scala>time{var mut_var=MMap[Int,Int]();for(i)}
运行时间:574174400ns
scala>time{var imut_var=Map[Int,Int]();for(i)}
运行时间:860938800ns
scala>time{val mut_val=MMap[Int,Int]();用于(i)}
运行时间:1103283000ns
scala>time{var mut_var=MMap[Int,Int]();for(i)}
运行时间:1166532600ns
scala>time{var imut_var=Map[Int,Int]();for(i)}
运行时间:2926954500ns
我还添加了可变变量,即使很难,也没有多大意义。 它的性能非常类似于可变val,只是为了完成这幅图。 但不可变var的性能要差得多

因此,不可变var与可变val的代价是性能下降(以及更广泛的内存使用!)。有人能再解释一下支付这个价格的意义吗?具体例子值得赞赏


谢谢

有很多方法可以回答这个问题(也有很多评论反驳可变val总是表现更差的说法),但这里有一个短语:范围和副作用

不可变变量的作用域仅限于其声明的位置,将其作为参数传递或分配给另一个变量通常会按预期进行操作。
另一方面,可变val无论在何处使用和传递,都会感觉到状态发生变化

考虑一个应用程序,在该应用程序中,您希望使用从默认值继承的不同配置运行多个worker。(假设
TIMEOUT\u1
=
t1
PARALLEL\u1
=
pf1
TIMEOUT\u2
=
t2
等)

使用不可变变量

var defaultConfig = immutable.Map("timeout" → "5", "parallelFactor" → "4")
var worker1Config = defaultConfig
var worker2Config = defaultConfig

worker1Config += "timeout" → sys.env("TIMEOUT_1")
worker1Config += "parallelFactor" → sys.env("PARALLEL_FACTOR_1")

worker2Config += "timeout" → sys.env("TIMEOUT_2")
worker2Config += "parallelFactor" → sys.env("PARALLEL_FACTOR_2")

println(defaultConfig) // Map(timeout -> 5, parallelFactor -> 4)
println(worker1Config) // Map(timeout -> t1, parallelFactor -> pf1)
println(worker2Config) // Map(timeout -> t2, parallelFactor -> pf2)
具有可变VAL

val defaultConfig = mutable.Map("timeout" → "5", "parallelFactor" → "4")
val worker1Config = defaultConfig
val worker2Config = defaultConfig

worker1Config += "timeout" → sys.env("TIMEOUT_1")
worker1Config += "parallelFactor" → sys.env("PARALLEL_FACTOR_1")

worker2Config += "timeout" → sys.env("TIMEOUT_2")
worker2Config += "parallelFactor" → sys.env("PARALLEL_FACTOR_2")

println(defaultConfig) // Map(parallelFactor -> pf2, timeout -> t2)
println(worker1Config) // Map(parallelFactor -> pf2, timeout -> t2)
println(worker2Config) // Map(parallelFactor -> pf2, timeout -> t2)

您可以看到,尽管几乎所有代码都是相同的,但使用可变VAL引入了一个不明显的错误(特别是如果这些代码段位于不同的函数中,而不是全部在一起)。

您永远不会将单个元素一个接一个地添加到这样的不可变映射中。你更愿意做一些像
(1到2000000).view.map(i=>i->i).toMap
,这应该更快。不变性的优点在互联网上随处可见。你所做的具体研究是什么?好的,你测试了使用可变映射迭代构建2M元素映射会更快。这是意料之中的。但是你不能将这个结果概括为到处使用可变结构更快更简单。@Carcigenicate,我认为问题很清楚。例如,mut-val和imut-var都不是“引用透明的”。没有一个是线程安全的。等等。预期答案是为什么imut var可能更好的一个具体原因-就像kag0的答案中所解释的那样。@DrYWit您的问题很清楚,但是询问不变性的好处是什么是一个过于模糊的问题,正如我提到的,已经通过一些研究回答了这个问题。如果你需要根据先前的研究对某一点进行澄清,那么这将是一个很好的问题。很好的例子,谢谢。defaultConfig的原因很明显,但有点出乎意料的是,可变映射中的“顺序”没有得到保留。我只测试了一个工作配置和3对(键->值)worker1Config+=“timeout”->“t1”;worker1Config+=“并行因子”->“pf1”;worker1Config+=“dummy”->“dummy”,结果低于scala.collection.mutable.Map[String,String]=Map(parallelFactor->pf1,dummy->dummy,timeout->t1)