如何在(akka)Actor中处理多个Promise?

时间:2012-12-03 17:18:18

标签: scala akka actor

我有一个负责处理http调用的Akka actor。我使用scala dispatch通过API发送多个HTTP请求:

urls.foreach { u
  val service = url(u)
  val promise = Http(service OK as.String).either
  for(p <- promise)
  {
     p match
     {
       case Left(error) =>
         faultHandler(error)
       case Right(result) =>
         resultHandler(result)
     }
  }

resultHandler函数中,我增加一个实例变量nbOfResults并与我已完成的调用次数进行比较。

def resultHandler(result:String)
{
  this.nbOfResults++
  ...
  if(nbOfResults == nbOfCalls)
    // Do something
}

安全吗?如果两个呼叫同时返回结果,可以同时访问nbOfResults变量吗?

目前,我认为actor或多或少等同于一个线程,因此回调函数不会同时执行。这是对的吗?

4 个答案:

答案 0 :(得分:3)

以下是仅使用调度的Alexey Romanov响应的变体:

//Promises will be of type Array[Promise[Either[Throwable, String]]]
val promises = urls.map { u =>
    val service = url(u)

    Http(service OK as.String).either
}

//Http.promise.all transform an Iterable[Promise[A]] into Promise[Iterable[A]]
//So listPromise is now of type Promise[Array[Either[Throwable, String]]]
val listPromise = Http.promise.all(promises)

for (results <- listPromise) {
    //Here results is of type Array[Either[Throwable, String]]

    results foreach { result =>
        result match {
            Left(error) => //Handle error
            Right(response) => //Handle response
        }
    }
}

答案 1 :(得分:2)

有一个更好的方法:

val promises = urls.map {u =>
  val service = url(u)
  val promise = Http(service OK as.String).either
}

val listPromise = Future.sequence(promises)

listPromise.onComplete { whatever }

答案 2 :(得分:2)

我同意Alexey Romanov的回答。无论您选择同步http请求的方式,请注意您处理承诺完成的方式。你的直觉是正确的,因为并发访问可能出现在actor的状态中。处理此问题的更好方法是执行以下操作:

def resultHandler(result: String) {
    //on completion we are sending the result to the actor who triggered the call
    //as a message
    self ! HttpComplete(result)
}

并且在演员的接收函数中:

def receive = {
    //PROCESS OTHER MESSAGES HERE
    case HttpComplete(result) => //do something with the result
}

这样,你确保处理http结果不会从外部违反actor的状态,而是从actor的receive循环中这是正确的方法

答案 3 :(得分:1)

val nbOfResults = new java.util.concurrent.atomic.AtomicInteger(nbOfCalls)

// After particular call was ended    
if (nbOfResults.decrementAndGet <= 0) {
  // Do something
}

[编辑]删除了AtomicReference CAS的旧答案 - while(true),compareAndSet等