【问题标题】:Akka avoiding wrapping future when responding to non-Actor codeAkka 在响应非 Actor 代码时避免包装未来
【发布时间】:2012-09-09 11:06:44
【问题描述】:

我正在使用 Akka 2 制作一个小型缓存 Actor,为了让 Actor 不被阻塞,我在 futures 中执行所有计算。然而一个问题是这个actor还需要与不是它本身在actor中的代码进行交互,所以我需要使用“ask”模式来获取一个值。

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

例如

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 函数,但恐怕这不会被视为对非参与者代码的“响应”

【问题讨论】:

    标签: scala akka future


    【解决方案1】:

    将 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搭建缓存系统的文章。 http://letitcrash.com/post/30509298968/case-study-an-auto-updating-cache-using-actors

    【讨论】:

    • 但这不是发送两次吗?一次是 Future[Future[...]](发件人!Future { ... }),另一次是 Future[...](发件人!值)?它适用于非参与者调用代码吗?您如何使用 CalcResult 消息?
    • 更新了代码。实际上这个解决方案来自文章(letitcrash.com/post/30509298968/…),我现在没有时间验证它。希望这对您有帮助。
    • 呵呵,谢谢!实际上,几个小时前我正在阅读该资源,因为它谈到了 Akka 和缓存。我想我读得不够透彻,在仔细检查后,它似乎或多或少地按照我想要的方式做事。如果它按预期工作,我会选择你的答案作为正确的答案
    • 没错。向询问者发送一个值将完成未来。并且发送 Status.Failure 会发送一个异常(见doc.akka.io/docs/akka/2.0.2/scala/futures.html
    • @sourcedelica 不错,我尝试在 github 上的 askpatterns 源代码中寻找它,但找不到(我找到了一个特殊的 ActorRef)。那么假设它是一个 Actor 是否正确地完成了一个 Future 与它首先收到的任何东西然后死去?在那种情况下,它非常漂亮,我应该能够使用 pipeTo。遗憾的是没有记录(无法在 Futures 页面或 Actors 页面上找到它)。
    【解决方案2】:

    这是解决方案:

    val f = myCache ? GetOrCalc("myKey", myCalculation)
    
    def receive = {
        case GetOrCalc(key, calculation) =>
            if (keyNotExists) Future { calculation() } pipeTo sender
            else sender ! cacheMap(key)
    }
    

    Send-And-Receive-Future">http://doc.akka.io/docs/akka/2.0.3/scala/actors.html#Ask_Send-And-Receive-Future

    【讨论】:

    • 奇怪的是,这正是我在原始伪代码中的内容,甚至没有对其进行测试,因为我认为 pipeTo 不会作为“响应”工作。这就是我没有测试而只是假设的结果!虽然说实话,这种行为不在我上面提到的文档中。非常感谢维克多!
    • 我想知道“pipeTo sender”如何安全地访问发件人。我明白为什么你不能从 Future 中访问 sender,但是为什么 pipeTo sender 没有同样的问题。是因为 pipeTo 在 Future 完成之前在 actor 的上下文中评估 sender 吗?
    • 它不会关闭发送方“then”,而是关闭发送方“now”的值。这有意义吗?
    • 是的,我想是的。通过查看 pipeTo 的源代码,我可以看到它立即在隐式创建的 PipeableFuture 对象上调用 pipeTo,该对象将立即评估 sender,但通过使用 onComplete 回调延迟了实际 actor 发送的执行。一如既往,感谢您帮助解决这个问题,Rob
    • 进一步的评论,大概是在下面的代码示例中,发件人没有被安全地访问。或者我还没有掌握这些未来事物是如何运作的? :-)
    猜你喜欢
    • 2013-10-26
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 2013-04-30
    • 1970-01-01
    • 1970-01-01
    • 2018-01-21
    相关资源
    最近更新 更多