在Akka中使用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

我有一个关于如何正确处理IO阻塞操作的问题,我读到正确的模型,它将阻塞操作包装到
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 _ => }

}