我有一个负责处理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或多或少等同于一个线程,因此回调函数不会同时执行。这是对的吗?
答案 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等