【问题标题】:All Scala futures completed已完成所有 Scala 期货
【发布时间】:2015-05-17 23:18:25
【问题描述】:

我有一个 akka 演员,其中我在 scala 中有几个期货,它们只做一些额外的工作并将计算保存到共享变量中。主要工作完成后,我想等待这些“额外”的未来并回复一个答案。简单的代码是这样的:

....
val replyTo = sender()
var informationCollector = InformationCollector()
val mainFuture: Future[GetMainInformation] = ...
val aFuture: Future[GetExtraInformationA] =...
val bFuture: Future[GetExtraInformationB] =...
val cFuture: Future[GetExtraInformationC] =...

// now I want all the futures to write their result
// and save it into the informationCollector and then
// after all have executed, reply back to Sender all the collected Data.

使用这种方法,我有 2 个问题。我不确定在期货的 onSuccess 调用中访问 InformationCollector 是否安全,我也想让它易于扩展(因此可以轻松添加其他收集器)。

到目前为止,我想出了这个解决方案,但我不确定它是否正确

// IMPORTANT: firstly add map for all of the extraInfoFutures to add that information into collector
// this will create aFutureMapped, bFutureMapped, cFutureMapped
roomFuture onComplete {
      case Success(mainInfo: GetMainInformation) => {
           informationCollector = informationCollector.copy(mainInformation=mainInfo)
           Future.sequence(List(aFutureMapped,bFutureMapped,cFutureMapped)) onComplete { _ =>
               replyTo ! informationCollector
           }

      }
}

非常感谢任何帮助。

【问题讨论】:

    标签: scala future


    【解决方案1】:

    我不确定我是否完全理解您的问题,但我至少可以为第一个问题提供答案。

    访问onComplete 中的可变状态可能是不安全的。实际上,它使演员的全部目的无效。如果您访问可变状态,您应该始终通过参与者的邮箱进行访问,例如self ! ModifyState(newValue).

    这里的问题是onComplete 方法与参与者不在同一个线程中,这导致两个线程可能同时修改相同数据并因此改变状态具有与通常并发的所有相同问题状态突变(竞争条件等)。

    对于第二个问题,我将通过self ! TypeAExtraValue(someValue) 从不同类型的额外期货中收集值,然后在收到所有额外值后发送收集器(例如TypeAInfoCollector)。如果使用得当,actor 可以解决这个问题,因为它们一次只处理一条消息。

    代码可能如下所示:

    val extraInfoFuture = getExtraInfo()
    val infoCollector = new Collector()
    
    extraInfoFuture onComplete {
      case Success(extraInfo) => self ! ExtraInfo(extraInfo) 
    }
    
    ...
    
    def receive = {
      case ExtraInfo(info) => {
        infoCollector.collect(info)
        if(infoCollector.collectedAll) sender() ! infoCollector
      }
    }
    

    【讨论】:

    • 你好jubis,谢谢你的回答。多个 onComplete 线程访问同一个变量是正确的。但是,即使变量仅在 receive() 方法的范围内(它不是整个 actor 类的属性)并且只有一个 onComplete,这是否也是一个问题?我仍然有多个 onCompletes 访问该变量,所以这仍然是一个问题。
    • 当然,您可以尝试使用范围来防止出现问题。但是,有一天您可能会不小心将变量移动到另一个地方而忘记了作用域的用途。只使用一个onComplete 仍然是不安全的:onComplete 仍将位于 Actor 本身之外的另一个线程中,因此有两个线程正在修改状态。
    • 把它想象成 Swing :) (你只能在 UI 线程中访问 UI)
    • 但实际上我在所描述的未来甚至创建之前初始化了 receive() 方法中的变量。初始化变量后,创建future,然后future是之后访问该变量的唯一地方,所以我认为这可能不是问题。还是您在这里发现了问题?
    • 这似乎风险较小 - 不会出现从多个线程访问同一个变量的情况。但是,此解决方案无法扩展(第二个未来会产生风险),并且仍然存在您更改代码并在 接收内部的其他地方访问相同变量的风险。
    猜你喜欢
    • 2022-11-04
    • 2023-03-16
    • 1970-01-01
    • 2023-03-03
    • 2021-09-21
    • 2022-08-06
    • 2020-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多