Option [Object]上的Scala匹配并非详尽无遗,Akka接收函数中的Some(o)和None

时间:2014-02-10 20:21:45

标签: multithreading scala jvm akka actor

对于下面选项[实体] 的匹配,第三种情况需要详尽无遗。为什么?

entitiesMap 是包含不可变 Map [UUID,Entity] var 。它在一个Akka Actor中被访问和更新,以避免线程问题。以下是接收功能的摘录:

class WorldActor extends Actor {

  var world: World = null

  override def receive = {

    case WorldSet(w) =>
      world = w

    // get that state and apply it to its entity
    case s: State if (world != null) =>
      val uuid = new UUID(s.getUuid().getL1(), s.getUuid().getL2())
      world.entitiesMap.get(uuid) match {
        case Some(ent) =>
          // Update entity's state
          ent.setEntityState(s)
        case None =>
          Log.error("World doesn't contain entity uuid: " + uuid)
        case other =>
          Log.error("Received unknown message: " + other)
      }

    case AddEntity(ent) if (world != null && ent != null) =>
      if (!world.entitiesMap.contains(ent.uuid))
        world.entitiesMap += ent.uuid -> ent

    case RemoveEntity(ent) if (world != null && ent != null) =>
      if (world.entitiesMap.contains(ent.uuid))
        world.entitiesMap -= ent.uuid

    case other => // ignore
  }

}

class World {
  // Entity container
  var entitiesMap = Map[UUID,Entity]()
}

以上代码会不时报告:

Received unknown message: None

为什么上面没有 case None 模式才能捕获它?

修改

我发现消息 State 就在消息 AddEntity 之前,即当 entitiesMap 尚未包含<时em>实体由消息 State 引用。

01:52 ERROR: [State] Received unknown message: None
uuid: 1b234d30-92ae-11e3-aa12-7071bcb09717
Thread: 152

01:52 ERROR: [State] Received unknown message: None
uuid: 1b234d30-92ae-11e3-aa12-7071bcb09717
Thread: 32

01:52  INFO: [AddEntity] 1b234d30-92ae-11e3-aa12-7071bcb09717: Cube@2f9c3beb
Thread: 152

毕竟这可能是一个线程问题吗?在一个演员?

编辑2

根据下面的海报建议,我已经记录了其他的类名,类加载器引用和类文件路径。他们都是一样的。

编辑3

其他==无 false

other.eq(无) false

other.equals(无) false

other.hashCode == None.hashCode

System.identityHashCode(其他)!= System.identityHashCode(无)

2 个答案:

答案 0 :(得分:6)

这听起来像一个类加载器/类路径问题,其中None$由两个类加载器加载而两个None $ .Module $不比较相等。

由于Map是不可变的,因此在添加之后,您已经创建了一个新的Map。假设外部加载器加载了新Map的类;然后当该地图返回None时,它将返回外星人None。

请注意,当您添加到非常小的地图时,它会使用new来创建下一个更大的地图;但经过一些这样的分配后,它会切换到HashMap。因此,竞争类加载器可能会改变您获得的地图的明显行为。

我不仅打印出类名,还打印出类加载器和加载类的位置。

答案 1 :(得分:1)

根据每个人的建议告诉我这个问题是一个类加载器问题和printing stack trace at None's construction time,我把它缩小到我使用Kryo来在通过网络传输之前序列化消息。

Kryo似乎是singleton objects can lead to my problem exactly的默认行为。 Kryo每次反序列化时都会重新加载 None ,导致 None System.identityHashCode 不同。

问题是class reloading,解决方案是使用一个知道如何正确处理Scala对象以进行序列化的库,例如chill-scala

package com.twitter.chill

// Singletons are easy, you just return the singleton and don't read:
// It's important you actually do this, or Kryo will generate Nil != Nil, or None != None

class SingletonSerializer[T](obj: T) extends KSerializer[T] {
  def write(kser: Kryo, out: Output, obj: T) {}
  def read(kser: Kryo, in: Input, cls: Class[T]): T = obj
}