1

我正在使用 scala dispatch (0.11.0) 库向远程服务器发送 HTTP GET 请求。我想在执行请求之后的代码之前等待响应。

我的要求是:

val req = :/("myurl.com") <:< myheaders OK as.Response(identity)

如果我写:

val future = http(req)
future()
var res: String = null
future onComplete {
    case Success(r) => res = r.getResponseBody
    case _ => println("KO")
}
println(res)

我得到空值。如果我写的话也是这种情况:

val future = http(req)
var res: String = null
while (!future.isCompleted) {
    Thread.sleep(1000)
}
future onComplete {
    case Success(r) => res = r.getResponseBody
    case _ => println("KO")
}
println(res)

但是使用以下代码:

val future = http(req)
var res: String = null
future onComplete {
    case Success(r) => res = r.getResponseBody
    case _ => println("KO")
}
while (!future.isCompleted) {
    Thread.sleep(1000)
}
println(res)

我得到了预期的回应。

有人明白这一点吗?在我看来,调用 Thread.sleep 不是一件好事,有人能给我一个提示,告诉我应该如何正确处理这个问题吗?

编辑:@Randal Schulz 感谢您的帮助,但正如您在评论中发布的那样,我无法验证您的答案。

由于我的问题是等待(并且什么都不做),直到我得到对 HTTP GET 请求的有效响应,我认为一个令人满意的方法是使用 Await.result。我从我的代码中删除了副作用。我使用 option 方法来处理 Future 失败(因为我只对成功感兴趣),并且我以经典方式处理超时异常。

我想我可以像之前提到的那样做,留在未来,但我需要更多的练习......

4

2 回答 2

3

TL;博士

对于在异步工作流中工作,我能给你的最好建议是,进入 a 的内容Future保留在Future.

回答

问题是您不知道何时Future完成,因此如果您想使用异步进程,您将不得不以异步方式编写。您编写的代码永远不会在Future您创建的代码上停止或阻塞,因此在它创建Future并将其交给另一个线程的那一刻,当前线程可以自由地评估res变量。

因此,将您正在执行的大部分操作置于如下流程中:

 myFuture map (func1) map (func2) map (func3) onComplete{
   case Success(value) => println(value.getResponseBody)
   case _ => println('KO')
 }

不要像你一样尝试通过副作用访问某些东西。

如果你真的很聪明并且你有几个Future,你可以编写它们:

val f1 = myFuture map(func1)
val f2 = myOtherFuture map(func2) map (func3)

val f3 = for{
  v1 <- f1
  v2 <- f2
} yield functionTakingBoth(v1, v2)

f3 onComplete{
  //and do stuff here
}
于 2014-01-30T15:21:39.553 回答
-1

我终于设法用 futures 写出我想要的东西:

def loop(): Future[String] = {
    val future = http(req).option
    future flatMap ((x: Option[Response]) => x match {
        case Some(rep) => rep.getResponseBody
        case None => loop()
    }
}

现在我可以使用这个函数的结果,而无需明确地等待响应的到来。

于 2014-01-31T12:44:44.923 回答