"Principles of Reactive Programming" 之<Actors are Distributed> (2)

devos發表於2014-12-22

Actor Path

我們知道actor是有層級的(hierarchical),第、每個actor在它的父actor的名字空間下都有一個名字。這樣就構成了一個樹狀的結構,就像是檔案系統。每個actor就像檔案系統裡的一個資料夾,因為每個actor都可以有子actor,因此,它們更像是資料夾,而不是檔案。

val system = ActorSystem("HelloWorld")
val ref = system.actorOf(Props[Greeter], "greeter")
println(ref.path)
// prints: akka://HelloWorld/user/greeter

在這上面這段程式碼裡,greeter的父actor是user(所有使用者通過system.actorOf建的actor,都是user的子actor)。

greeter的path是akka://HelloWorld/user/greeter

這是一個URI。

其中authority part是akka://HelloWorld,這也是HelloWorld這個actor system的地址。akka://是一個協議,說明這是一個本地的actor path.

/user/greeter,是actor的path,這裡就是greeter這個actor的path.

它們加起來就表示greeter這個actor的URI。

其實,每個actor system可以有多個地址,比如上邊的HelloWorld當遠端訪問時,它的地址可以是 akka.tcp://HelloWorld@10.2.4.6:6565。其中akka.tcp說明這個這個actor system需要通過tcp協議訪問,名字是HelloWorld, IP為10.2.4.6,埠為6565。如果訪問這個actor system裡的greeter這個actor,那麼地址是akka.tcp://HelloWorld@10.2.4.6:6565/user/greeter

這說明每個actor system都可以多個地址,如果它能通過多個協議或者多個IP地址訪問。

The difference between ActorPath and ActorRef

ActorPath和檔案路徑一樣,你可以隨便拼湊檔案路徑,即使它所指向的地方並沒有檔案。但是ActorRef一定指向一個存在的檔案(對於actor,更像是資料夾,因為actor可以有子actor)。

每個ActorRef都會有一個path, 指向這個ActorRef。但是ActorPath可以指向一個並不存在的ActorRef,因此ActorPath是不可以被watch的,但是ActorRef可以。因為,ActorRef只能被以有限的方式獲取,這些獲取方式保證了它一定是某個已經在工作的actor的reference。無法獲取一個並不存在的actor的ActorRef。 也因為如此,向一個ActorPath傳送訊息和向ActorRef傳送訊息是不同的。

另外,對於ActorRef,如果一個ActorPath指向的actor停止了,那麼它的parent可以用同樣的名字啟動另一個actor,那麼新的actor和已經終止的actor有同樣的actorPath,但是它們有不同的ActorRef。ActorRef的最後有一個UID,它標識了ActorRef的不同。

Actor names are unique within a parent, but can be reused.

  • ActorPath is the full name, whether the actor exists or not.
  • ActorRef points to an actor which was started; an incarnation.

ActorPath can only optimistically send a message.

ActorRef can be watched.

ActorRef example: akka://HelloWorld/user/greeter#43438347   (print 一個ActorRef顯示的值)

Resolving an ActorPath

case class Resolve(path: ActorPath)
case class Resolved(path: ActorPath, ref: ActorRef)
case class NotResoved(path: ActorPath)
case class ToBeResolved(path: ActorPath, client: ActorRef)

class Resolver extends Actor{
  def receive = {
    case Resolve(path) => context.actorSelection(path) ! Identify(ToBeResolved(path, sender()))
    case ActorIdentity(ToBeResolved(path, client), Some(actorRef)) => client ! Resolved(path, actorRef)
    case ActorIdentity(ToBeResolved(path, client), None) => client ! NotResoved(path)
  }
}

  有些時候我們不能直接獲取ActorRef,比如另一個ActorSystem裡,不是你建立的一個actor。這時候就需要另一套機制了,就是Identify和ActorIdentify。每一個Actor都能處理Identify訊息,把自己的ActorRef封裝於ActorIdentify中返回給sender。這就是通過通訊來獲取ActorRef, 總之, ActorRef是不能憑空先出來一個的,它一定代表一個存在的actor。

Relative Actor Paths

Looking up a grand-child:

  •  context.actorSelection("child/grandchild")

Looking up a sibling:

  • context.actorSelection("../sibling")

Looking up from the local root:

  • context.actorSelection("/user/app")

Broadcasting using wildcasts:

  • context.actorSelection("/user/controllers/*")

actor path的語義跟檔案系統的path非常類似。

相關文章