actor binary tree lab4

forward 与 ! (tell) 的差异,举个例子:

Main(当前actor): topNode ! Insert(requester, id=1, ele = 2)

topNode: root ! Insert(requester, id=1, ele = 2)

对于root而言,Insert消息的来源是topNode

假如第二行替换为

topNode: root forward Insert(requester, id=1, ele = 2)

此时,对于root而言,Insert消息的来源是Main

从上面的例子可以看出,! 和 forward之间是有差别的,但是差别本身比较tricky,会增加理解的成本,所以传递消息时,把消息的actorRef作为参数传递会简单很多。

在lab4中,就需要考虑到!与forward的异同点

testcase 的 code

  test("proper inserts and lookups") {
    val topNode = system.actorOf(Props[BinaryTreeSet])

    topNode ! Contains(testActor, id = 1, 1)
    expectMsg(ContainsResult(1, false))

    topNode ! Insert(testActor, id = 2, 1)
    topNode ! Contains(testActor, id = 3, 1)

    expectMsg(OperationFinished(2))
    expectMsg(ContainsResult(3, true))
  }

结合topNode,与root的处理逻辑

  val normal: Receive = {
//    这个forward非常重要,不能写成 !,不然第一个testcase都不过去
    case operation: Operation => root ! operation
    case GC => {
      //garbageCollecting需要先变,因为节点的复制可能会很久
      val newRoot = createRoot
      context.become(garbageCollecting(newRoot))
      root ! CopyTo(newRoot) 
      
    }
    case _ => println("unknown operation")
  }
    
// root 的处理逻辑
  case Insert(requester, id, elem) => if(this.elem == elem) { if(this.removed) this.removed = false requester ! OperationFinished(id) } else { val child = if(this.elem > elem) Left else Right if(subtrees contains child) subtrees(child) ! Insert(requester, id, elem) else { subtrees += child -> context.actorOf(props(elem, false)) requester ! OperationFinished(id) } }

 

在source code中,topNode收到消息后,把消息传递给root,root认为消息的来源是topNode。假如消息不绑定requester参数,那么通过sender获得actor是tiopNode,而不是main。我们在testcase中做assertion的话,肯定就是错的。

另外,上例中用到了testActor,它是implicit变量,用于处理发送到main中的消息。主要是测试方便。

 

一个debug了5个小时的bug

case msg: Operation =>
        pendingQueue = pendingQueue.enqueue(msg)

pendingQueue.enqueue(msg) 并不能更新pendingQueue自己,必须重新赋值才行。

你可能感兴趣的:(binary)