scala - 是否将同步 HTTP 请求包装在被视为 CPU 或 IO 约束的 Future 中?
问题描述
考虑以下两个片段,其中第一个使用 scalaj-http 请求包装Future
,而第二个使用 async-http-client
使用全局 EC同步使用 Future 包装的客户端
object SyncClientWithFuture {
def main(args: Array[String]): Unit = {
import scala.concurrent.ExecutionContext.Implicits.global
import scalaj.http.Http
val delay = "3000"
val slowApi = s"http://slowwly.robertomurray.co.uk/delay/${delay}/url/https://www.google.co.uk"
val nestedF = Future(Http(slowApi).asString).flatMap { _ =>
Future.sequence(List(
Future(Http(slowApi).asString),
Future(Http(slowApi).asString),
Future(Http(slowApi).asString)
))
}
time { Await.result(nestedF, Inf) }
}
}
使用全局 EC 的异步客户端
object AsyncClient {
def main(args: Array[String]): Unit = {
import scala.concurrent.ExecutionContext.Implicits.global
import sttp.client._
import sttp.client.asynchttpclient.future.AsyncHttpClientFutureBackend
implicit val sttpBackend = AsyncHttpClientFutureBackend()
val delay = "3000"
val slowApi = uri"http://slowwly.robertomurray.co.uk/delay/${delay}/url/https://www.google.co.uk"
val nestedF = basicRequest.get(slowApi).send().flatMap { _ =>
Future.sequence(List(
basicRequest.get(slowApi).send(),
basicRequest.get(slowApi).send(),
basicRequest.get(slowApi).send()
))
}
time { Await.result(nestedF, Inf) }
}
}
片段正在使用
- 慢慢模拟慢速 API
- scalaj-http
- async-http-client sttp 后端
- 时间
前者需要 12 秒,而后者需要 6 秒。似乎前者的行为好像受 CPU 限制,但我不明白这是怎么回事,因为Future#sequence
应该并行执行 HTTP 请求?为什么包装的同步客户端的Future
行为与正确的异步客户端不同?异步客户端在幕后将调用包装在 Futures 中,难道不是这种情况吗?
解决方案
Future#sequence 应该并行执行 HTTP 请求吗?
首先,Future#sequence
不执行任何操作。它只是产生一个在所有参数完成时完成的未来。如果 EC 中有空闲线程,则立即开始构建期货的评估(执行)。否则,它只是将其提交给某种队列。我敢肯定,在第一种情况下,您可以单线程执行期货。
println(scala.concurrent.ExecutionContext.Implicits.global) -> 并行度 = 6
不知道为什么会这样,可能其他5个线程由于某种原因总是很忙。您可以尝试使用 5-10 个线程显式创建的新 EC。
与 Async 情况的不同之处在于您不自己创建未来,它由库提供,内部不会阻塞线程。它启动异步过程,“订阅”结果,并返回未来,当结果到来时完成。
实际上,异步库内部可能有另一个 EC,但我怀疑。
顺便说一句,Futures 不应该包含没有blocking
. 否则,您可能会阻塞主线程池 (EC),并且您的应用程序将完全冻结。
推荐阅读
- c++ - 使用初始化列表分段构建地图
- networking - 如何在没有应答的情况下监听 tcp 端口?
- c - BN_print_fp() 函数总是在 OpenSSL 中以十六进制输出 BIGNUM 对象?
- javascript - 如何创建一个html按钮来调用一个css脚本
- c - Modulo % 仅在 C 中打印一个零位
- android - Android用笔画宽度绘制矢量的正确方法
- java - Java类路径不同的顺序是否给出“未找到方法错误”
- javascript - 如何在 JavaScript 中拼接多个元素(不遵循连续顺序)?
- c# - XML 解析以获取 XElement 列表中的特定标记值
- view - 如何刷新每个新蜡烛的脚本?