Scala Akka在响应非参与者代码时避免包装未来

Scala Akka在响应非参与者代码时避免包装未来,scala,akka,future,Scala,Akka,Future,我正在用Akka 2制作一个小型缓存演员,为了使演员不被阻挡,我在futures中执行所有计算。然而,问题是,这个参与者还需要与参与者中不存在的代码交互,因此我需要使用“ask”模式来获取值 我的问题是,在使用ask模式时,如何避免将我计算的未来包装在另一个未来中 比如说 val f = myCache ? GetOrCalc("myKey", myCalculation) // this will be a Future[Future[...]] but I would like a Futu

我正在用Akka 2制作一个小型缓存演员,为了使演员不被阻挡,我在futures中执行所有计算。然而,问题是,这个参与者还需要与参与者中不存在的代码交互,因此我需要使用“ask”模式来获取值

我的问题是,在使用ask模式时,如何避免将我计算的未来包装在另一个未来中

比如说

val f = myCache ? GetOrCalc("myKey", myCalculation) // this will be a Future[Future[...]] but I would like a Future[...]

// meanwhile, inside the actor
def receive = {
    case GetOrCalc(key, calculation) =>
        if (keyNotExists) sender ! Future { calculation() } // calculation() is long-running
        else sender ! cacheMap(key)
}

理想情况下,我可以使用Future.pipeTo函数,但恐怕这不会被算作非参与者代码的“响应”

将onComplete添加到未来的计算中

def receive = {
    case GetOrCalc(key, calculation) =>
        if (keyNotExists) // calculation() is long-running
            Future { calculation() } onComplete {
                case Right(result) => result match {
                        case Some(value) => sender ! value
                        case None => sender ! Status.Failure(new Exception("Cannot find the value"))
                    }
                case Left(ex) =>
                    sender ! Status.Failure(ex)

            }
        else sender ! cacheMap(key)
}
还有一篇关于使用Akka构建缓存系统的文章

这就是解决方案:

val f = myCache ? GetOrCalc("myKey", myCalculation)

def receive = {
    case GetOrCalc(key, calculation) =>
        if (keyNotExists) Future { calculation() } pipeTo sender
        else sender ! cacheMap(key)
}

发送和接收未来“>http://doc.akka.io/docs/akka/2.0.3/scala/actors.html#Ask_Send-并接收Future

但这不发送两次吗?一次发送Future[Future[…](发送方!Future{…}),另一次发送Future[…](发送方!值)?它是否适用于非参与者调用代码?如何使用CalcResult消息?更新了代码。实际上,此解决方案来自文章()我现在没有时间来验证它。希望这对你是一个有用的线索。呵呵,谢谢!我在几个小时前阅读了那个来源,实际上是因为它谈到了Akka和缓存。我想我读得不够透彻,在仔细检查之后,它似乎或多或少按照我想要的方式做事情。如果它能像expec一样工作的话ted我会选择正确的答案。向询问者发送一个值将完成以后的工作。发送状态。失败将发送一个异常(请参阅)@sourcedelica nice,我尝试在github上的askpatterns源中查找,但找不到(我找到了一个特殊的ActorRef).那么,假设这是一个演员用他首先收到的东西完成了一个未来,然后就死了,这是正确的吗?在这种情况下,它非常漂亮,我应该能够使用Pippeto。可惜这没有记录在案(在期货页面和演员页面上都找不到)。奇怪的是,这正是我原始伪代码中的内容,甚至没有对其进行测试,因为我假设pipeTo不会作为“响应”工作。这就是我不进行测试而只是假设得到的结果!尽管实话告诉你,这种行为不在我上面提到的文档中。非常感谢Viktor!我想知道如何“pipeTo sender”“正在安全访问发件人。我理解为什么您不能在将来访问发件人,但为什么pipeTo发件人没有相同的问题。这是因为pipeTo在将来完成之前在参与者的上下文中评估发件人吗?它不会关闭发件人“然后”,而是关闭发件人“现在”的值。这有道理吗?是的,我想有道理。通过查看pipeTo的源代码,我可以看到它在隐式创建的PipeableFuture对象上立即调用pipeTo,该对象将立即计算发送方,但通过使用onComplete回调延迟实际actor send的执行。和往常一样,感谢您帮助我们解决这个问题,RobOne可能会对下面的代码示例发表进一步的评论,发件人没有被安全访问。还是我还没有掌握这些未来事物是如何运作的?:-)