我有一个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
}
}
}
任何帮助都非常感谢。
答案 0 :(得分:1)
我不确定我是否完全理解你的问题但我至少可以在第一期提供答案。
在onComplete
中访问可变状态可能不安全。实际上它会使演员的整个目的无效。如果您访问可变状态,则应始终通过actor的邮箱进行操作,例如self ! ModifyState(newValue)
。
这里的问题是onComplete
方法与actor不在同一个线程中导致可能有两个线程同时修改相同数据的情况,因此改变状态会产生所有相同的问题并发状态突变(竞争条件等)。
对于第二个问题,我只会通过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
}
}