2014-10-27 54 views
2

我有一個演員來控制GUI。 爲了保證即時響應(沒有卡在屏幕上),我將一個PinnedDispatcher分配給這個actor。爲什麼akka演員和線程是如此不同

val system = ActorSystem("sys1") 
def createMonitor(clients:Seq[ActorRef],init_QPS:Int) = system.actorOf(Props(new MonitorGUI)).withDispatcher("my-pinned-dispatcher")) 

配置文件就像

my-pinned-dispatcher { 
    executor = "thread-pool-executor" 
    type = PinnedDispatcher 
} 

演員的程序是這樣的

class MonitorGUI() extends Actor { 
    val rate = 1000 milliseconds 
    val scheduler = context.system.scheduler 
    def receive = { 

    case GUIRefresh => 
     GUI.refresh() 
    case StartMonitor => 
     scheduler.schedule(rate + (300 milliseconds), rate ,self, GUIRefresh) 
    } 
} 

調度應該調用 「刷新」 每一秒。 但是,當有許多其他演員執行大量計算(例如98%CPU)時,調度程序無法保證每秒都會「刷新」。例如,GUI卡住了5秒鐘。 但是純線程程序比男主角程序更爲敏感,就像這樣:

new Thread(new Runnable { 
    override def run(): Unit = { 
    while (true){ 
     GUI.refresh 
     Thread.sleep(1000) 
    } 
    } 
}).start() 

我不知道爲什麼線程和演員是如此不同。因爲這個演員應該有自己的線程。應該沒有區別。

回答

2

參與者不像線程那樣可搶佔;當一個actor開始處理消息時,它將繼續處理直到它完成該消息,並且只有這樣纔可以運行另一個actor。這是爲了高吞吐量而設計的一個決定(它消除了上下文切換),但是在編寫代碼時需要注意它。

要麼確保沒有單個消息的處理運行時間超過您希望的延遲時間(可能是將計算拆分爲小單元併發送新消息以觸發每個步驟),要麼爲您的單獨的執行上下文/調度程序使用計算繁重的演員和對延遲敏感的演員。 (理想情況下,您可能希望確保兩個上下文中的線程總數等於物理CPU內核數量,以避免上下文線程阻塞另一個線程)。