Scala 参与者和未来:指onComplete中的参与者消息
在重构其他程序员编写的actor代码时,我遇到了在actorScala 参与者和未来:指onComplete中的参与者消息,scala,akka,future,Scala,Akka,Future,在重构其他程序员编写的actor代码时,我遇到了在actorA中使用Future.onComplete回调的情况,这与使用akka.pattern.pipe的最佳实践背道而驰。这是一个坏主意,因为它暴露了竞争条件的可能性,因为未来的实例可能会在不同的线程上执行 查看代码,我们发现在onComplete块中既没有sender也没有任何可变的vars被引用,因此它看起来相当安全,至少在这个特定的场合是如此。然而,有一个灰色区域让我感到疑惑,那就是对url的引用,尤其是对text的引用 与问题类似,是
A
中使用Future.onComplete
回调的情况,这与使用akka.pattern.pipe
的最佳实践背道而驰。这是一个坏主意,因为它暴露了竞争条件的可能性,因为未来的
实例可能会在不同的线程上执行
查看代码,我们发现在onComplete
块中既没有sender
也没有任何可变的var
s被引用,因此它看起来相当安全,至少在这个特定的场合是如此。然而,有一个灰色区域让我感到疑惑,那就是对url
的引用,尤其是对text
的引用
与问题类似,是否可能发生竞态条件,即在调用onComplete
回调时,text
的值已经引用了不同的参与者消息,从而导致所有hell崩溃
class B extends akka.actor.Actor {
def receive = {
case urlAndText: (String, String) => // do something
}
}
class A extends akka.actor.Actor {
case class Insert(url: String)
def fileUpload(content: String): String = ??? // returns the url of the uploaded content
val b = context.actorOf(Props(classOf[B]))
def receive = {
case text: String =>
Future {
fileUpload(text)
} onComplete {
case Success(url) =>
b ! Insert(url, text) // will this be
}
}
}
在这种情况下,您将不会遇到任何竞争条件,尽管正如您所指出的,通常以这种方式构造代码不是一个特别好的主意 对
url
和text
的引用都很好。url
的值只是一个成功完成的未来的提取,它不会改变你是否是演员。text
的值是一个不可变的字符串,在将来关闭该值不会导致问题,因为该字符串实例是不可变的
正如您所指出的,关闭发送方或var是一个问题,这是因为作为可变对象,这些值在未来完成时可能会发生变化,而不可变值即使在关闭它们时也会保持不变。对
文本的引用应该可以。区别在于文本的每个“实例”都是绑定到当前匹配块范围的新变量(从案例文本开始…
)。因此,所创建的未来
与文本
的值很接近
这与sender
(或sender()
脱糖时)不同,后者实际上是在Actor
特征上定义的一种方法,它返回被调用的Actor最近收到的消息的发送者的ActorRef
,因此在以后调用时可以给出不同的值(当最后调用Future
的onComplete
时)
您对使用onComplete
的怀疑也是正确的。更好的选择是:
case text: String =>
Future {
fileUpload(text)
} map { url =>
Insert(url, text)
} pipeTo b
现在,故障也将被发送到b
,而不是被悄悄地吞没