<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ### Actor的生命周期 在Actor系統中的路徑代表一個“地方”,這可能被一個存活著的的actor占用著。最初,路徑(除了系統初始化角色)是空的。當`actorOf()`被調用時,指定一個由通過`Props`描述給定的路徑角色的化身。一個actor化身由路徑和一個UID確定。重新啟動僅僅交換Props定義的Actor 實例,但化身與UID依然是相同的。 當該actor停止時,化身的生命周期也相應結束了。在這一刻時間上相對應的生命周期事件也將被調用和監管角色也被通知終止結束。化身被停止之后,路徑也可以重復被通過`actorOf()`方法創建的角色使用。在這種情況下,新的化身的名稱跟與前一個將是相同的而是UIDs將會有所不同。 一個`ActorRef`總是代表一個化身(路徑和UID)而不只是一個給定的路徑。因此,如果一個角色停止,一個新的具有相同名稱創建的舊化身的`ActorRef`不會指向新的。 在另一方面`ActorSelection`指向該路徑(或多個路徑在使用通配符時),并且是完全不知道其化身當前占用著它。由于這個原因導致`ActorSelection`不能被監視到。通過發送識別信息到將被回復包含正確地引用(見通過角色選擇集識別角色)的`ActorIdentity`的`ActorSelection`來解決當前化身`ActorRef`存在該路徑之下。這也可以用`ActorSelection`類的`resolveOne`方法來解決,這將返回一個匹配`ActorRef`的`Future`。 ![](https://box.kancloud.cn/2016-02-22_56ca7f422b7be.png "") ### Actor生命周期Hook: Akka Actor定義了下列的生命周期回調鉤子(Hook): > - preStart:在actor實例化后執行,重啟時不會執行。 > - postStop:在actor正常終止后執行,異常重啟時不會執行。 > - preRestart:在actor異常重啟前保存當前狀態。 > - postRestart:在actor異常重啟后恢復重啟前保存的狀態。當異常引起了重啟,新actor的postRestart方法被觸發,默認情況下preStart方法被調用。 ### 啟動Hook 啟動策略,調用preStart Hook,一般用于初始化資源.在創建一個Actor的時候,會調用構造函數,之后調用preStart。 preStart的默認形式: ~~~ def preStart(): Unit = () ~~~ ### 重啟Hook 所有的Actor都是被監管的,i.e.以某種失敗處理策略與另一個actor鏈接在一起。如果在處理一個消息的時候拋出的異常,Actor將被重啟。這個重啟過程包括上面提到的Hook: > 1. 要被重啟的actor的`preRestart`被調用,攜帶著導致重啟的異常以及觸發異常的消息; 如果重啟并不是因為消息的處理而發生的,所攜帶的消息為None,例如,當一個監管者沒有處理某個異常繼而被它自己的監管者重啟時。 這個方法是用來完成清理、準備移交給新的actor實例的最佳位置。它的缺省實現是終止所有的子actor并調用`postStop`。 > 1. 最初`actorOf`調用的工廠方法將被用來創建新的實例。 > 1. 新的actor的`postRestart`方法被調用,攜帶著導致重啟的異常信息。 actor的重啟會替換掉原來的actor對象;重啟不影響郵箱的內容, 所以對消息的處理將在`postRestart hook`返回后繼續。觸發異常的消息不會被重新接收。在actor重啟過程中所有發送到該actor的消息將象平常一樣被放進郵箱隊列中。 preRestart和postRestart的默認形式: ~~~ def preRestart(reason: Throwable, message: Option[Any]): Unit = { context.children foreach { child ? context.unwatch(child) context.stop(child) } postStop() } def postRestart(reason: Throwable): Unit = { preStart() } ~~~ 解釋一下重啟策略的詳細內容: > 1. actor被掛起 > 1. 調用舊實例的 supervisionStrategy.handleSupervisorFailing 方法 (缺省實現為掛起所有的子actor) > 1. 調用preRestart方法,從上面的源碼可以看出來,preRestart方法將所有的children Stop掉了,并調用postStop回收資源 > 1. 調用舊實例的supervisionStrategy.handleSupervisorRestarted方法(缺省實現為向所有剩下的子actor發送重啟請求) > 1. 等待所有子actor終止直到 preRestart 最終結束 > 1. 再次調用之前提供的actor工廠創建新的actor實例 > 1. 對新實例調用 postRestart > 1. 恢復運行新的actor ### 終止Hook `postStop hook`一般用于回收資源。Actor在被調用postStop之前,會將郵箱中剩下的message處理掉(新的消息變成死信了)。Actor是由UID和Path來唯一標識的,也就是說ActorRef也是通過UID和Path來定位。在Actor被Stop之后,新的Actor是可以用這個Path的,但是舊的ActorRef是不能用的,因為UID不一樣。 這個hook保證在該actor的消息隊列被禁止后才運行,i.e.之后發給該actor的消息將被重定向到ActorSystem的`deadLetters`中。 postStop的默認形式: ~~~ def postStop(): Unit = () ~~~ ### 各種Hook的順序關系圖解 ![](https://box.kancloud.cn/2016-02-22_56ca7f4255e3f.jpg "") ### Akka的actor生命周期示例代碼 下面用Kenny類演示生命周期函數的調用順序: ~~~ import akka.actor._ class Kenny extends Actor { println("entered the Kenny constructor") override def preStart: Unit = { println("kenny: preStart") } override def postStop: Unit ={ println("kenny: postStop") } override def preRestart(reason: Throwable, message: Option[Any]): Unit = { println("kenny: preRestart") println(s" MESSAGE: ${message.getOrElse("")}") println(s" REASON: ${reason.getMessage}") super.preRestart(reason, message) } override def postRestart(reason: Throwable): Unit = { println("kenny: postRetart") println(s" REASON: ${reason.getMessage}") super.postRestart(reason) } def receive = { case ForceRestart => throw new Exception("Boom!") case _ => println("Kenny received a message") } } case object ForceRestart object LifecycleDemo extends App{ val system = ActorSystem("LifecycleDemo") val kenny = system.actorOf(Props[Kenny], name="Kenny") println("sending kenny a simple String message") kenny ! "hello" Thread.sleep(1000) println("make kenny restart") kenny ! ForceRestart Thread.sleep(1000) println("stopping kenny") system.stop(kenny) println("shutting down system") system.shutdown } ~~~ `pre*`和`post*`方法和actor的構造函數一樣,都是用來初始化或關閉actor所需的資源的。 上面的代碼中,`preRestart`和`postRestart`調用了父類的函數實現,其中`postRestart`的默認實現中,調用了`preStart`方法。 打印信息: ~~~ sending kenny a simple String message entered the Kenny constructor kenny: preStart Kenny received a message make kenny restart kenny: preRestart MESSAGE: ForceRestart REASON: Boom! kenny: postStop [ERROR] [01/16/2016 21:51:46.584] [LifecycleDemo-akka.actor.default-dispatcher-4] [akka://LifecycleDemo/user/Kenny] Boom! java.lang.Exception: Boom! at Examples.Tutorials.Kenny$$anonfun$receive$1.applyOrElse(Test4_LifecycleDemo.scala:24) at akka.actor.Actor$class.aroundReceive(Actor.scala:480) at Examples.Tutorials.Kenny.aroundReceive(Test4_LifecycleDemo.scala:4) at akka.actor.ActorCell.receiveMessage(ActorCell.scala:526) at akka.actor.ActorCell.invoke(ActorCell.scala:495) at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257) at akka.dispatch.Mailbox.run(Mailbox.scala:224) at akka.dispatch.Mailbox.exec(Mailbox.scala:234) at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) entered the Kenny constructor kenny: postRetart REASON: Boom! kenny: preStart stopping kenny shutting down system kenny: postStop ~~~ ### Actor系統中的監管 在Actor系統中說過,**監管描述的是actor之間的關系:監管者將任務委托給下屬并對下屬的失敗狀況進行響應。** 當一個下屬出現了失敗(i.e.拋出一個異常),它自己會將自己和自己所有的下屬掛起然后向自己的監管者發送一個提示失敗的消息。取決于所監管的工作的性質和失敗的性質,監管者可以有4種基本選擇: > 1. 讓下屬繼續執行,保持下屬當前的內部狀態 > 1. 重啟下屬,清除下屬的內部狀態 > 1. 永久地終止下屬 > 1. 將失敗沿監管樹向上傳遞 重要的是始終要把一個actor視為整個監管樹形體系中的一部分,這解釋了第4種選擇存在的意義(因為一個監管者同時也是其上方監管者的下屬),并且隱含在前3種選擇中:讓actor繼續執行同時也會繼續執行它的下屬,重啟一個actor也必須重啟它的下屬,相似地終止一個actor會終止它所有的下屬。被強調的是一個actor的缺省行為是在重啟前終止它的所有下屬,但這種行為可以用Actor類的`preRestart hook`來重寫;對所有子actor的遞歸重啟操作在這個hook之后執行。 每個監管者都配置了一個函數,它將所有可能的失敗原因(i.e.Exception)翻譯成以上四種選擇之一;注意,這個函數并不將失敗actor本身作為輸入。我們很快會發現在有些結構中這種方式看起來不夠靈活,會希望對不同的下屬采取不同的策略。在這一點上我們一定要理解監管是為了組建一個遞歸的失敗處理結構。如果你試圖在某一個層次做太多事情,這個層次會變得復雜難以理解,這時我們推薦的方法是增加一個監管層次。 Akka實現的是一種叫“父監管”的形式。Actor只能由其它的actor創建,而頂部的actor是由庫來提供的——每一個創建出來的actor都是由它的父親所監管。這種限制使得actor的樹形層次擁有明確的形式,并提倡合理的設計方法。必須強調的是這也同時保證了actor們不會成為孤兒或者擁有在系統外界的監管者(被外界意外捕獲)。還有,這樣就產生了一種對actor應用(或其中子樹)自然又干凈的關閉過程。 ### 生命周期監控(臨終看護DeathWatch) 在Akka中生命周期監控通常指的是DeathWatch。 除了父actor和子actor的關系的監控關系,每個actor可能還監視著其它任意的actor。因為actor創建后,它活著的期間以及重啟在它的監管者之外是看不到的,所以對監視者來說它能看到的狀態變化就是從活著變到死亡。所以監視的目的是當一個actor終止時可以有另一個相關actor做出響應,而監管者的目的是對actor的失敗做出響應。 **監視actor通過接收Terminated消息來實現生命周期監控。如果沒有其它的處理方式,默認的行為是拋出一個DeathPactException異常。為了能夠監聽Terminated消息,你需要調用ActorContext.watch(targetActorRef)。調用ActorContext.unwatch(targetActorRed)來取消對目標角色的監聽。需要注意的是,Terminated消息的發送與監視actor注冊的時間和被監視角色終止的時間順序無關。例如,即使在你注冊的時候目標actor已經死了,你仍然能夠收到Terminated消息。** 當監管者不能簡單的重啟子actor而必須終止它們時,監視將顯得非常重要。例如,actor在初始化的時候報錯。在這種情況下,它應該監視這些子actor并且重啟它們或者稍后再做嘗試。 另一個常見的應用案例是,一個actor或者它的子actor在無法獲得需要的外部資源時需要失敗。如果是第三方通過調用system.stop(child)方法或者發送PoisonPill消息來終止子actor時,監管者也將會受到影響。 ### 說明 為了在其它actor結束時(i.e.永久終止,而不是臨時的失敗和重啟)收到通知,actor可以將自己注冊為其它actor在終止時所發布的 `Terminated`消息的接收者。這個服務是由actor系統的`DeathWatch`組件提供的。 注冊一個監控器的代碼: ~~~ import akka.actor.{ Actor, Props, Terminated } class WatchActor extends Actor { val child = context.actorOf(Props.empty, "child") context.watch(child) // <-- 這是注冊所需要的唯一調用 var lastSender = system.deadLetters def receive = { case "kill" ? context.stop(child); lastSender = sender case Terminated(`child`) ? lastSender ! "finished" } } ~~~ 要注意`Terminated`消息的產生與注冊和終止行為所發生的順序無關。多次注冊并不表示會有多個消息產生,也不保證有且只有一個這樣的消息被接收到:如果被監控的actor已經生成了消息并且已經進入了隊列,在這個消息被處理之前又發生了另一次注冊,則會有第二個消息進入隊列,因為一個已經終止的actor注冊監控器會立刻導致`Terminated`消息的發生。 可以使用`context.unwatch(target)`來停止對另一個actor的生存狀態的監控,但很明顯這不能保證不會接收到`Terminated`消息因為該消息可能已經進入了隊列。 ### DeathWatch代碼示例: DeathWatch的作用是,當一個actor終止時,你希望另一個actor收到通知。 使用`context.watch()`方法來聲明對一個actor的監控。 下面是示例代碼: ~~~ import akka.actor._ class Jason extends Actor { def receive = { case _ => println("jason got a message") } } class Parent extends Actor { // start Jason as a child, then keep an eye on it val jason = context.actorOf(Props[Jason], name="Jason") context.watch(jason) def receive = { case Terminated(jason) => println("OMG, they killed jason") case _ => println("parent received a message") } } object DeathWatchDemo extends App{ val system = ActorSystem("DeathWatchDemo") val parentActor = system.actorOf(Props[Parent], name="Parent") // look up jason, then kill it println("kill the child actor") val jasonActor = system.actorSelection("/user/Parent/Jason") jasonActor ! PoisonPill Thread.sleep(5000) println("calling system.shutdown") system.shutdown } ~~~ 當Jason被殺死后,Parent actor收到`Terminated(jason)`消息。 **轉載請注明作者Jason Ding及其出處** [Github博客主頁(http://jasonding1354.github.io/)](http://jasonding1354.github.io/) [GitCafe博客主頁(http://jasonding1354.gitcafe.io/)](http://jasonding1354.gitcafe.io/) [CSDN博客(http://blog.csdn.net/jasonding1354)](http://blog.csdn.net/jasonding1354) [簡書主頁(http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)](http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles) **Google搜索jasonding1354進入我的博客主頁**
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看