在Akka中使用IO/阻塞操作的最正确方法
我有一个关于如何正确处理IO阻塞操作的问题,我读到正确的模型,它将阻塞操作包装到在Akka中使用IO/阻塞操作的最正确方法,akka,Akka,我有一个关于如何正确处理IO阻塞操作的问题,我读到正确的模型,它将阻塞操作包装到Future中,并使用此对象,而不是在actor内部调用阻塞操作 但我认为这至少有两种解决方案 case class AccountBalance(id: Int, userId: Int, total: Int) object AccountBalance { def getUserAccountBalance(userId: Int)( implicit ec: ExecutionContext
Future
中,并使用此对象,而不是在actor内部调用阻塞操作
但我认为这至少有两种解决方案
case class AccountBalance(id: Int, userId: Int, total: Int)
object AccountBalance {
def getUserAccountBalance(userId: Int)(
implicit ec: ExecutionContext): Future[AccountBalance] = {
Future {
AccountBalance(1, userId, 1)
}
}
def updateAccountBalance(id: Int, total: Int)(implicit ec: ExecutionContext): Future[AccountBalance] = {
Future {
AccountBalance(id, 1, total)
}
}
// Main logic
def getAndInc(userId: Int)(implicit ec: ExecutionContext) = {
getUserAccountBalance(userId).flatMap { balance =>
updateAccountBalance(balance.id, balance.total + 1)
}
}
}
在第一种方法中,我在actor内部使用AccountBalanece.getAndInc
方法:
class Approach1 extends Actor {
implicit val executionContext = context.dispatcher
def receive = {
case Calculate(userId) =>
AccountBalance.getAndInc(userId) pipeTo sender
}
}
另一个解决方案(对我来说更舒适)
哪种解决方案更好(或既危险又不可用)
关于ExecutionContext
的第二个问题,例如,我使用context.dispatcher
对于实际应用程序,我使用下一个:
class A extends Actor {
implicit val executionContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(10))
override def postStop = {
executionContext.shutdown()
}
def receive = { case _ => }
}
如果在actor停止后使用
executionContext.shutdown
,这是关闭线程池并释放所有资源的正确方法?因为需要响应式编程来确保执行线程未被阻塞。因此,任何阻塞操作都应该由不同的执行上下文来处理,以避免阻塞分派actors命令/消息的线程。我使用第二种模式,其中我的参与者使用“变成”并转到另一个行为,等待来自阻塞操作的响应。这是为了不处理任何新请求并丢失原始发件人actorRef。如果您仍然希望参与者接收其他消息并发送这些消息,则需要在原始发件人和收到的响应之间建立链接
是的,这样做就行了,但我建议在创建线程池时要非常小心,并在阻塞参与者之间共享它们。请注意,如果关机引发异常,并且您只想关闭actor A,而不是所有akka系统,那么supervisor不会重新启动actor A。您能清理示例代码吗?您的问题涉及到“阻塞操作”,但无论是
AccountBalance.getUserAccountBalance
还是AccountBalance.updateAccountBalance
都不是阻塞操作,因此根本不需要未来操作…举个例子,您可能会认为所有方法都是带有阻塞的方法
class A extends Actor {
implicit val executionContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(10))
override def postStop = {
executionContext.shutdown()
}
def receive = { case _ => }
}