【发布时间】:2020-11-15 22:46:56
【问题描述】:
考虑以下两个 sn-ps,其中第一个使用 Future 包装 scalaj-http 请求,而第二个使用 async-http-client
Sync 客户端使用全局 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) }
}
}
Async 客户端使用全局 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) }
}
}
sn-ps 正在使用
- Slowwly 模拟慢速API
- scalaj-http
- async-http-clientsttp 后端
- time
前者需要 12 秒,而后者需要 6 秒。似乎前者的行为好像受 CPU 限制,但我不明白这是怎么回事,因为Future#sequence 应该并行执行 HTTP 请求?为什么包装在 Future 中的同步客户端的行为与正确的异步客户端不同?异步客户端在幕后将调用包装在 Futures 中,难道不是这种情况吗?
【问题讨论】:
-
AFAIK,它应该被认为是 IO 有界的,因为线程除了等待不会做任何事情。适当的异步客户端不会阻塞真正的计算线程,因此 ec 应该不会进行更多调用,而 sycn 客户端会阻塞线程。 - 顺便说一句,您可能希望使用
traverse,因此在定义列表时不会启动请愿,您可能希望使用同步客户端添加三分之一的sn-p,但包装在scala concurrent.blocking块上。 -
@LuisMiguelMejíaSuárez 行为不是由所使用的执行上下文类型决定的吗,既然我们对两个客户端使用相同的
globalEC,那么行为是否应该不同? -
为什么?就像说如果我们使用 JVM 运行两个相似但具有不同复杂性的函数应该执行相同的函数。 - 顺便说一句,
global在您的环境中的性质是什么?您是否在只有一个线程的环境中运行? -
嗯,是的,我相信 Scastie 使用单个线程作为其
global。 - 真正的异步客户端应该比blocking做得更好,因为blocking(当工作时,例如对于单线程 ec 它什么都不做) 只会创建一个新线程来阻塞.而真正的异步客户端不应该阻塞任何东西,而是使用回调来工作。看看 JS 中的事件循环,你不能阻塞它,你也不能创建一个新的来阻塞,一切都必须是真正的异步。 -
@LuisMiguelMejíaSuárez
println(scala.concurrent.ExecutionContext.Implicits.global)在 scastie 中提供parallelism = 6。
标签: scala concurrency future scalaj-http sttp