Scala 只有在处理完所有消息后,才向Akka actor询问结果

Scala 只有在处理完所有消息后,才向Akka actor询问结果,scala,akka,actor,akka-http,akka-actor,Scala,Akka,Actor,Akka Http,Akka Actor,我试图将一大块文本分割成多个段落,并通过调用外部API来并发处理它。 每次来自段落API的响应时,都会更新一个不可变列表 一旦段落被处理并且列表被更新,我想请求参与者在接下来的步骤中使用最终状态 以下方法的问题是,我永远不知道何时处理所有段落。 一旦所有段落都处理完毕并且列表是最终的,我需要返回targetStore def main(args: Array[String]) { val source = Source.fromFile("input.txt")

我试图将一大块文本分割成多个段落,并通过调用外部API来并发处理它。 每次来自段落API的响应时,都会更新一个不可变列表

一旦段落被处理并且列表被更新,我想请求参与者在接下来的步骤中使用最终状态

以下方法的问题是,我永远不知道何时处理所有段落。 一旦所有段落都处理完毕并且列表是最终的,我需要返回targetStore

def main(args: Array[String]) {
    val source = Source.fromFile("input.txt")
    val extDelegator = new ExtractionDelegator()
    source.getLines().foreach(line => extDelegator.processParagraph(line))
    extDelegator.getFinalResult()

  }


case class Extract(uuid: UUID, text: String)

case class UpdateList(text: String)

case class DelegateLambda(text: String)


case class FinalResult()


class ExtractionDelegator {
 
  val system = ActorSystem("ExtractionDelegator")
  val extActor = system.actorOf(Props(classOf[ExtractorDelegateActor]).withDispatcher("fixed-thread-pool"))
  implicit val executionContext = system.dispatchers.lookup("fixed-thread-pool")

  def processParagraph(text: String) = {
    extActor ! Extract(uuid, text)

  }

  def getFinalResult(): java.util.List[String] = {
    implicit val timeout = Timeout(5 seconds)
    val askActor = system.actorOf(Props(classOf[ExtractorDelegateActor]))
    val future = askActor ? FinalResult()
    val result = Await.result(future, timeout.duration).asInstanceOf[java.util.List[String]]
    result
  }

  def shutdown(): Unit = {
    system.terminate()
  }

}


/* Extractor Delegator actor*/
class ExtractorDelegateActor extends Actor with ActorLogging {
  var targetStore:scala.collection.immutable.List[String] = scala.collection.immutable.List.empty

  def receive = {
    case Extract(uuid, text) => {
      context.actorOf(Props[ExtractProcessor].withDispatcher("fixed-thread-pool")) ! DelegateLambda(text)

    }
    case UpdateList(res) => {
      targetStore = targetStore :+ res
    }
    case FinalResult() => {
      val senderActor=sender()
      senderActor ! targetStore

    }
  }
}

/* Aggregator actor*/
class ExtractProcessor extends Actor with ActorLogging {
  def receive = {
    case DelegateLambda(text) => {
      val res =callLamdaService(text)
      sender ! UpdateList(res)
    }

  }

  def callLamdaService(text: String): String = { 
    //THis is where external API is called.  
    Thread.sleep(1000)
    result
  }
}

不知道为什么要在这里使用演员,最简单的方法是

// because you call external service, you have back async response most probably
def callLamdaService(text: String): Future[String]
为了处理你的文本,你需要

implicit val ec = scala.concurrent.ExecutionContext.Implicits.global // use you execution context here
Future.sequence(source.getLines().map(callLamdaService)).map {results =>
  // do what you want with results
}
如果您仍然想使用actors,可以将
callLamdaService
替换为
processparagration
,这将在内部向工作者actor执行
ask
,后者返回结果(因此,
processparagration
的签名将是
def processparagration(text:String):Future[String]

如果您仍然想启动多个任务,然后请求结果,那么您只需要使用
上下文。当您增加每个
提取
消息的工作人员数量并减少每个
更新列表
消息的工作人员数量时,就可以使用
接收(worker:Int)
。对于非零数量的处理工人,您还需要执行
FinalResult
的延迟处理