为什么不可变编程比可变编程更受欢迎?

时间:2017-10-27 12:44:28

标签: multithreading scala immutability

我从available article所有关于此主题的内容是

不可变对象的主要优点是进行并发编程。 因此,如果任何应用程序使用如此多的线程,那么我们可以使用不变性。

这里我的问题是:如果应用程序不需要多个线程,仍然首选不可变编程?因为为每一次更改创建一个新的对象副本可能会非常昂贵。(如果是的话)

2 个答案:

答案 0 :(得分:1)

考虑一下:

class Time(t: Double) {
  private var time = t // Danger: mutable field
  def getTime = time
  def setTime(t: Double): Unit = time = t
}

val startAt = new Time(5.0)
val someOtherTime = startAt
someOtherTime.setTime(10.0)

// What does startAt.getTime return?

在这个简单的示例中,您可能(或可能不会)惊讶地发现,在someOtherTime.setTime(10.0)返回后,startAt.getTime将具有值10.0而不是5.0 。你有没有期待,特别是考虑到startAtval

鉴于您已经看过代码,也许这是预期的。但是,如果您只是使用Time而没有查看其内部结构,我猜测您会对此行为感到非常惊讶。可变对象的状态可以在您不知道更改的情况下进行更改 - 尤其是在必须同步访问Time.time的多线程环境中 - 但即使是单线程情况也会引入意外的复杂性。

保持对象不可变使得它们易于推理。当这些对象代表值类型时,不变性实际上是必不可少的。 (在任何不可变的主要编程语言或库中命名单个值类型。)

关于单线程与多线程编码的另一个观点:如果您正在编写单线程应用程序,那么您可能会完全忽略线程安全问题。但是,我认为在一般情况下这有点短视。所有新处理器都有多个内核,并且有迹象表明处理器将在未来几年内获得越来越多的内核。如果您想编写响应迅速的高性能代码,那么您将需要使用线程安全库来编写多线程应用程序。

如果您正在编写非线程安全的代码,并且它包含许多展示共享可变状态的可变对象,那么您将不得不做一个大量的重构使其适用于多线程应用程序。另一方面,如果你的对象是不可变的,并且没有共享的可变状态,那么这项工作将变得更加容易。

顺便提及,完全可以在函数,类等中使用可变状态,条件是不共享可变状态(即,在外部可见)。这样你就可以获得可变状态性能的好处,而没有缺点。

答案 1 :(得分:0)

我完全同意即使在单线程程序中,不可变对象也更容易推理。但是,有时使用可变数据更为实际,例如,如果性能至关重要(我们的计算机针对变异操作进行了优化),或者您正在使用的库本身具有状态。

我还要补充一点,Scala不是编写纯功能程序的最佳语言。 Haskell,PureScript,Idris等语言更适合恕我直言任务。对于某些多线程程序,以纯函数方式编写Scala程序绝对值得花费额外的麻烦。