據我了解 Akka 并行性,處理每個傳入訊息 Actor 使用一個執行緒。這個執行緒包含一個狀態。因此,順序訊息不共享此狀態。
但是 Actor 可能有一個 ExecutorContext 用于從 Future 執行回呼。這就是重點,我不再清楚地理解并行性。
例如,我們有以下演員:
class AnyActor(target: ActorRef) extends Actor {
implicit val ec: ExecutionContext = context.dispatcher
def receive = {
case messageA =>
val api = createApi()
val furureA: Future[F] = api.callA
api.close()
futureA.pipeTo(sender())
case messageB =>
val api = createApi()
val furureB: Future[F] = api.callB
api.close()
futureB.pipeTo(sender())
}
}
假設,Actor 接收 messageA,并且 Thread1 創建 api 的實體 - 我們稱之為“api1”。還有一個帶有 N 個執行緒的 executionContext。其中一個執行緒用于從 furureA 檢索結果。
我不明白的是,這 N 個執行緒與 Thread1 有何關聯。ExecutionContext 只為 Thread1 創建?或者它也是為 Thread2 創建的(在其中處理 messageB)?
uj5u.com熱心網友回復:
從廣義上講,actor 運行在調度程式上,該調度程式從池中選擇一個執行緒,并Receive為來自郵箱的一定數量的訊息運行該 actor 。通常不能保證一個actor 會在給定的執行緒上運行(忽略空的例子,比如具有單執行緒的池,或者總是在特定執行緒中運行給定actor 的調度程式)。
該調度程式也是一個 Scala ExecutionContext,它允許安排任意任務在其執行緒池上執行;此類任務包括Future回呼。
那么在你的演員中,當messageA收到a 時會發生什么?
- 演員呼叫
createApi()并保存它 - 它呼叫
callA方法api - 它關閉
api - 它安排將結果
callA可用時轉發給發件人 - 現在已準備好處理另一條訊息,并且可能會也可能不會實際處理另一條訊息
這實際上意味著什么取決于做什么callA。如果callA在執行背景關系上調度一個任務,它會在任務被調度并且回呼已經安排好后立即回傳未來;不能保證在回傳未來時任務或回呼已經執行。一旦回傳未來,您的演員就會關閉api(因此這可能發生在任務或回呼執行的任何時候)。
簡而言之,根據api實作方式(您可能無法控制它的實作方式)和實作細節,以下順序是可能的
- Thread1(處理
messageA)在調度器中設定任務 - Thread1 關閉
api并安排通過管道傳輸結果 - Thread2 開始執行任務
- Thread1 繼續處理其他一些訊息
- Thread2 的任務失敗,因為
api已被關閉
簡而言之,當混合Futures 和 actor 時,Akka 中的“單執行緒錯覺”可以被打破:任意多個執行緒都可以操縱 actor 的狀態。
在這個例子中,因為Futureland 和actorland之間唯一的共享狀態是處理單個訊息的本地狀態,所以還不錯:這里有效的一般規則是:
- 一旦您將可變(例如可關閉)狀態從參與者傳遞到未來(這包括,除非您可以絕對確定正在發生的事情,在該有狀態物件上呼叫回傳未來的方法),最好讓參與者忘記關于那個物件的存在
那怎么關閉api呢?
好吧,假設callA沒有做任何時髦的事情api(比如將實體保存在某個實體池中),在messageA完成處理和未來完成后,沒有任何東西可以訪問api. 所以最簡單也可能是最正確的做法是安排api在未來完成后關閉,沿著這些路線
val api = createApi()
val futureA: Future[F] = api.callA
futureA.foreach { _ => api.close() }
futureA.pipeTo(sender())
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/368219.html
