我有一个控制GUI的角色。 为了保证即时响应(屏幕上没有卡住),我将PinnedDispatcher分配给此actor。
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秒钟。 但是,纯线程程序比actor程序响应更快,如下所示:
new Thread(new Runnable {
override def run(): Unit = {
while (true){
GUI.refresh
Thread.sleep(1000)
}
}
}).start()
我想知道为什么线程和演员如此不同。因为这个actor应该有自己的线程。应该没有区别。
答案 0 :(得分:2)
演员不像线程那样是可抢占的;当一个actor开始处理一个消息时,它将继续处理直到它完成该消息,然后才能运行另一个actor。这是出于高吞吐量的设计决策(它消除了上下文切换),但在编写actor代码时需要注意它。
要么确保没有单个消息的处理运行时间超过所需的延迟(可能通过将计算分成小单位并发送新消息来触发每个步骤),或者为计算使用单独的执行上下文/调度程序 - 重要的演员和你对延迟敏感的演员。 (理想情况下,您可能希望确保两个上下文中的线程总数等于物理CPU核心数,以便上下文的线程都不会阻止另一个)。