Akka Ask 是否在当前线程上阻塞

spa*_*rkr 6 scala akka

我有一个场景,我必须通过用户的 ID 获取用户的详细信息。这是一个传入 HTTP 处理程序层的 HTTP 请求,我利用从请求中获取的 id,向 Actor 发送一条消息,然后 Actor 与数据库服务通信以获取用户。

现在,由于这是一个 HTTP 请求,我需要通过发回响应来满足该请求。所以我想到使用 Akka Ask 模式,但我有以下问题:

  1. 这会阻塞我当前的线程吗?

  2. 在我的例子中,使用询问模式来获取用户是一个可扩展的解决方案吗?我的意思是,在任何给定时间点,我都可能有数百到一百万用户调用此端点。使用询问模式来获取用户是一个好主意吗?

在代码中,它在我的 HTTP 控制器中看起来像这样

val result: Future[Any] = userActor ? FetchUser(id)
Run Code Online (Sandbox Code Playgroud)

在我的演员中,我会做以下事情:

case fetchUser: FetchUser => sender ! myService.getUser(fetchUser.id)
Run Code Online (Sandbox Code Playgroud)

Ram*_*gil 4

按照您提出问题的顺序回答您的问题:

  1. 不,使用?不会阻塞当前线程。它Future立即返回一个。然而,未来的结果可能无法立即获得。
  2. 如果您需要解决方案是“可扩展的”,并且您的服务能够进行多个并发查询,那么您可能需要使用一个Actor,以便可以?一次为多个服务提供服务,或者参见下面的仅 Futures 的可扩展解决方案。

期货独家

如果你的 Actors 没有缓存任何中间值,那么你可以直接使用 Futures 并避免 Actors 的繁琐(例如 Props、actorOf、receive、?、...):

import java.util.concurrent.Executors

import scala.concurrent.{ExecutionContext,Future}    

object ServicePool {      

  private val myService = ???

  val maxQueries = 11 //should come from a configuration file instead

  private val queryExecutionPool = 
    ExecutionContext.fromExecutor(Executors.newFixedThreadPool(maxQueries))

  type ID = ???

  /**Will only hit the DB with maxQueries at once.*/
  def queryService(id : ID) = 
    Future { myService getUser id }(queryExecutionPool)

}//end object ServiceQuery
Run Code Online (Sandbox Code Playgroud)

现在,您可以ServicePool.queryService根据需要多次调用,但服务不会受到多次调用maxQueries,并且不会出现任何 Actor:

val alotOfIDs : Seq[ID] = (1 to 1000000) map { i => ID(i)}

val results = alotOfIDs map ServicePool.queryService
Run Code Online (Sandbox Code Playgroud)