Scala 无种族条件的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) }

我有一个期货池,每个未来都使用相同的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)
  }
但在并发环境中,由于竞争条件,这种方法不起作用


我只知道解决这个问题的一个办法——在分裂到未来之前创建全球参与者。但这意味着我无法封装顶级库用户的大量隐藏工作。

你说得对,确保首先初始化全局参与者是正确的方法。难道你不能将它们绑定到一个同伴对象上并从那里引用它们,这样你就知道它们只会被初始化一次吗?如果您真的不能使用这种方法,那么您可以尝试这样的方法来查找或创建参与者。它与您的代码类似,但它包括在达到竞争条件(最多次数)时返回查找/创建逻辑(递归)的逻辑:

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
    ???
  }
}