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非常類似。