Fire and Forget模式

这是发送消息的推荐方式,不会阻塞地等待消息。它拥有最好的并发性和可扩展性。

actor ! "hello"

//or
actor.tell("hello", actor)

!操作符实际上暗地里还做了一件事儿,就是将发送者自身作为隐式参数传递。在AKKA的实现如下所示:

abstract class ActorRef ... {
  final def tell(msg: Any, sender: ActorRef): Unit = this.!(msg)(sender)
}

private[akka] class LocalActorRef private[akka]... {
  override def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit = actorCell.sendMessage(message, sender)
}

除非需要指定另外的ActorRef对象作为发送者,在Scala中,我们通常建议使用!操作符。

当要调用的actor不存在时,发送的消息会传递给dead letter actor。

通常情况下,我们会定义至少两个Actor来合作完成任务。一个Actor是任务的执行者,另一个Actor扮演任务的控制者。例如,我们需要一个LoadingActor去加载xml文件。此时,LoadingActor负责执行加载任务,至于何时执行该任务,执行完任务后应该怎么做,如何控制执行任务Actor的生命周期,都可以交给控制者。这个Actor必须定义为LoadingActor的父Actor,例如定义名为MasterActor。

sealed trait XmlMessage

case class SoftInfoMessage(fileName: String, fileNameIndex: Int, version: String) extends XmlMessage
case class FinishedMessage(fileName: String, index: Int)

class LoadingActor extends Actor {
  def receive = {
    case SoftInfoMessage(fileName, index, version) => {
      loading(fileName, index, version)
      sender ! new FinishMessage(fileName, index)
      context.stop(self)
    }
  }

  override def postStop() = {
    println("stop")
    super.postStop()
  }
}

class MasterActor(numberOfWorker: Int) extends Actor {
  def receive = {
    case "loading" => {
      (1 to numberOfWorker).foreach {
        index => {
          val loadingActor = context.actorOf(
          Props[LoadingActor], name = "workerRouter%d".format(index))
          loadingActor ! SoftInfoMessage("softinfo.xml", index, "4.13.10.01T09")
        }
      }
    }
    case FinishedMessage(fileName, index) => {
      println("%s.%d is loaded.".format(fileName, index))
    }
  }
}

MasterActor创建了指定数量的LoadingActor,然后通过创建的子actor发送SoftInfoMessage消息。LoadingActor收到该消息后,会异步地执行加载任务。一旦加载任务执行完毕,就通过sender发送FinishedMessage消息给MasterActor,然后终止自己。MasterActor在收到FinishedMessage消息后,就知道任务执行完毕了。