当您需要执行I / O(即数据库操作)时,actor模型(在Akka中)如何工作?
据我所知,阻塞操作会引发异常(并且由于Akka使用的Netty的性质,基本上会破坏所有并发性)。因此,我将不得不使用Future
或类似的东西 - 但我不理解并发模型。
future
(即future.get()
)中进行阻塞调用,那么阻止当前actor的执行;或者它会阻止所有演员的执行,直到阻止通话完成?基本情况是:
有没有更好的方法来实现这一目标?
答案 0 :(得分:27)
阻止操作不会在Akka中抛出异常。你可以阻止来自Actor的调用(你可能想要最小化,但这是另一个故事)。
至于netty(我假设你的意思是远程演员,因为这是在Akka中唯一使用netty的东西),尽快将你的工作传递给本地演员或未来(带回调)你担心时机或阻止netty以某种方式完成它的工作。
答案 1 :(得分:10)
阻塞操作通常不会抛出异常,但等待未来(例如使用!!
或!!!
发送方法)会抛出超时异常。这就是为什么你应该尽可能地使用“即发即忘”,使用有意义的超时值并尽可能选择回调。
akka actor无法显式连续处理多条消息,但您可以通过配置文件播放throughput
值。然后,如果其消息队列不为空,则actor将处理多个消息(即,其接收方法将被顺序调用几次):http://akka.io/docs/akka/1.1.3/scala/dispatchers.html#id5
阻止actor内部的操作不会“阻止”所有actor,但如果你在actor之间共享线程(推荐用法),调度程序的其中一个线程将被阻塞,直到操作恢复。因此,尽量尽量编写期货,并注意超时值。
3和4.我同意Raymond的回答。
答案 2 :(得分:1)
Raymond和范例所说的,但是,如果你想避免使线程池挨饿,你应该在scala.concurrent.blocking
中包装任何阻塞操作。
当然最好避免阻塞操作,但有时你需要使用阻塞的库。如果你将代码包装在blocking
中,它会让执行上下文知道你可能阻塞了这个线程,所以它可以根据需要分配另一个。
问题比范式描述更糟糕,因为如果你有几个阻塞操作,你最终可能会阻塞线程池中的所有线程并且没有自由线程。如果你的所有线程都被阻塞,那么你可能会遇到死锁,直到另一个演员/未来被安排好后才会发生。
以下是一个例子:
import scala.concurrent.blocking ... Future { val image = blocking { load_image_from_potentially_slow_media() } val enhanced = image.enhance() blocking { if (oracle.queryBetter(image, enhanced)) { write_new_image(enhanced) } } enhanced }
文档为here。