Scala 无种族条件的akka演员选择
我有一个期货池,每个未来都使用相同的akka参与者系统——系统中的一些参与者应该是全球性的,一些参与者只用于一个未来Scala 无种族条件的akka演员选择,scala,akka,concurrent.futures,Scala,Akka,Concurrent.futures,我有一个期货池,每个未来都使用相同的akka参与者系统——系统中的一些参与者应该是全球性的,一些参与者只用于一个未来 val longFutures = for (i <- 0 until 2 ) yield Future { val p:Page = PhantomExecutor(isDebug=true) Await.result( p.open("http://www.stackoverflow.com/") ,timeout = 10.seconds) }
val longFutures = for (i <- 0 until 2 ) yield Future {
val p:Page = PhantomExecutor(isDebug=true)
Await.result( p.open("http://www.stackoverflow.com/") ,timeout = 10.seconds)
}
但在并发环境中,由于竞争条件,这种方法不起作用
我只知道解决这个问题的一个办法——在分裂到未来之前创建全球参与者。但这意味着我无法封装顶级库用户的大量隐藏工作。你说得对,确保首先初始化全局参与者是正确的方法。难道你不能将它们绑定到一个同伴对象上并从那里引用它们,这样你就知道它们只会被初始化一次吗?如果您真的不能使用这种方法,那么您可以尝试这样的方法来查找或创建参与者。它与您的代码类似,但它包括在达到竞争条件(最多次数)时返回查找/创建逻辑(递归)的逻辑:
def findOrCreateActor[T=maxAttempts)
抛出新的RuntimeException(s“无法创建名为$name且已达到$maxAttempts的最大尝试次数的参与者”)
val selection=system.actorSelection“/user/$name”)
val fut=selection.resolveOne(超时).map(部分()).recover{
案例示例:ActorNotFound=>None
}
val REFPT=等待结果(未来,超时)
重新匹配{
案例部分(参考)=>参考
case None=>util.Try(system.actorOf(Props[T],name)).getOrElse(doFindOrCreate(depth+1))
}
}
doFindOrCreate()
}
现在,在创建actor时,重试逻辑将触发任何异常,因此您可能希望进一步指定(可能通过另一个
recover
combinator)当它得到一个<代码> ValueActReNAMEExtExe//C>时,只递归,但是你得到了这个想法。 < P>你可能想考虑创建一个管理器,它会关心创建“计数器”的演员。这样你就可以确保计数器演员的创建请求被序列化了。
object CounterManagerActor {
case class SelectActorRequest(name : String)
case class SelectActorResponse(name : String, actorRef : ActorRef)
}
class CounterManagerActor extends Actor {
def receive = {
case SelectActorRequest(name) => {
sender() ! SelectActorResponse(name, selectActor(name))
}
}
private def selectActor(name : String) = {
// a slightly modified version of the original selectActor() method
???
}
}
但是我应该避免两次运行这个CounterManager Actor,或者在未来{…}调用之外运行这个Actor-实际上,我的问题是如何避免这种构造,而不使用忽略双Actor或连续选择的异常之类的技巧。
def findOrCreateActor[T <: Actor : ClassTag](system:ActorSystem, name:String, maxAttempts:Int = 5):ActorRef = {
import system.dispatcher
val timeout = 0.1 seconds
def doFindOrCreate(depth:Int = 0):ActorRef = {
if (depth >= maxAttempts)
throw new RuntimeException(s"Can not create actor with name $name and reached max attempts of $maxAttempts")
val selection = system.actorSelection(s"/user/$name")
val fut = selection.resolveOne(timeout).map(Some(_)).recover{
case ex:ActorNotFound => None
}
val refOpt = Await.result(fut, timeout)
refOpt match {
case Some(ref) => ref
case None => util.Try(system.actorOf(Props[T],name)).getOrElse(doFindOrCreate(depth + 1))
}
}
doFindOrCreate()
}
object CounterManagerActor {
case class SelectActorRequest(name : String)
case class SelectActorResponse(name : String, actorRef : ActorRef)
}
class CounterManagerActor extends Actor {
def receive = {
case SelectActorRequest(name) => {
sender() ! SelectActorResponse(name, selectActor(name))
}
}
private def selectActor(name : String) = {
// a slightly modified version of the original selectActor() method
???
}
}