【问题标题】:Scala bug with immutable Map in concurrent program?并发程序中具有不可变 Map 的 Scala 错误?
【发布时间】:2009-12-22 17:40:23
【问题描述】:

我为棋盘游戏九人莫里斯写了一个蒙特卡洛播放器。一切基本上都是不可变的。该程序涉及大量期货(数百个)和大量修改不可变地图。有时我会遇到以下异常:

java.lang.NullPointerException
    at scala.collection.mutable.HashTable$class.elemHashCode(HashTable.scala:154)
    at scala.collection.immutable.HashMap.elemHashCode(HashMap.scala:41)
    at scala.collection.mutable.HashTable$class.findEntry(HashTable.scala:66)
    at scala.collection.immutable.HashMap.findEntry(HashMap.scala:41)
    at scala.collection.immutable.HashMap.undo$1(HashMap.scala:132)
    at scala.collection.immutable.HashMap.undo$1(HashMap.scala:130)
    at scala.collection.immutable.HashMap.makeCopy(HashMap.scala:154)
    at scala.collection.immutable.HashMap.makeCopyIfUpdated(HashMap.scala:161)
    at scala.collection.immutable.HashMap.update(HashMap.scala:66)
    at scala.collection.immutable.Map$class.$plus(Map.scala:66)
    at scala.collection.immutable.HashMap.$plus(HashMap.scala:41)
    at morris.players.MapBasedMorrisBoard.applyMove(MapBasedMorrisBoard.scala:30)
    at morris.players.MonteCarloPlayer$$anonfun$main$1$$anonfun$apply$1.apply(MonteCarloPlayer.scala:77)
    at morris.players.MonteCarloPlayer$$anonfun$main$1$$anonfun$apply$1.apply(MonteCarloPlayer.scala:77)
    at scala.actors.Futures$$anonfun$2$$anonfun$apply$1.apply(Future.scala:45)
    at scala.actors.Futures$$anonfun$2$$anonfun$apply$1.apply(Future.scala:44)
    at scala.actors.Reaction.run(Reaction.scala:78)
    at scala.actors.FJTask$Wrap.run(Unknown Source)
    at scala.actors.FJTaskRunner.scanWhileIdling(Unknown Source)
    at scala.actors.FJTaskRunner.run(Unknown Source)

我只使用不可变地图,所以我想知道这是由我自己的代码中的错误还是 scala 库中的错误引起的。查看跟踪时,您可以看到,在堆栈的下方有对可变 HashTable 的调用。也许这会导致并发问题?

我的程序中发生异常的代码只是将另一个集合添加到不可变 Map 中:

myMap ++ (someInteger -> aValue)

编辑: 没有并发的相同程序可以完美运行。

【问题讨论】:

  • 实际上,我非常希望这是 Scala 中的一个错误,我已经要求 SO 只是为了得到一些整合,以便将报告发布到 Scala 错误跟踪器。
  • 我在实现对“libscala”的 STM 支持时遇到了同样的问题。该错误出现在 scala 2.8 和 2.7.7 中。

标签: exception scala concurrency immutability


【解决方案1】:

我已经为 Scala 库提交了错误报告。事实证明,这是一个已知问题。 HashMap(在 Scala 中用作标准 Map 类型)的实现不适合在并发程序中使用,因为在幕后,它使用可变类型。这也可以在堆栈跟踪中观察到。 Scala 人希望在 2.8 中替换实现。

作为一种解决方法,建议使用真正不可变的 TreeHashMap。我已经这样做了,并且可以确认它有效。

Link to original bug report

【讨论】:

    【解决方案2】:

    它肯定会导致并发问题。至少将 Map 与 SynchronizedMap 混合使用。

    但请注意,这并不会给您任何交易保证。它只是确保地图不会在您的脚下损坏。

    【讨论】:

    • 这样做:带有 SynchronizedMap[Int,MorrisColor.Value] 的新 scala.collection.immutable.HashMap[Int,MorrisColor.Value]() 产生错误:(错误覆盖方法 excl in ... ) 有什么想法吗?
    • SynchronizedMap trait 位于可变包中,而我使用的是不可变的 Maps。你确定这是理智的事情吗?我真的必须将 SynchronizedMap 混入不可变类型吗?
    • @ziggystar - 不,我认为您根本不应该这样做。不可变映射确实在内部使用同步,这很奇怪,但“客户”不需要关心它
    • Ziggy,您说“我只使用可变映射”,所以我假设您使用的是可变映射。 :-) 不,对于不可变的,你不应该做任何事情——但确实可能存在错误。您使用的 Scala 版本是什么?
    • @Daniel 抱歉,这是一个错字。我只使用不可变的 Map,如堆栈跟踪中所示。这个错误发生在 2.7.7
    猜你喜欢
    • 2010-12-17
    • 1970-01-01
    • 2018-02-20
    • 2012-03-08
    • 2017-01-12
    • 1970-01-01
    • 2015-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多