考虑以下两个片段,其中第一个片段使用Future
封装scalajhttp请求,而第二个片段使用异步http客户端
使用全局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
- scalajhttp
- 异步http客户端sttp后端
- 时间
前者需要12秒,而后者需要6秒。前者的行为似乎是CPU绑定的,但我不明白这是怎么回事,因为Future#sequence
应该并行执行HTTP请求?为什么封装在Future
中的同步客户端的行为与正常的异步客户端不同?异步客户端是否也会做同样的事情,将Futures中的调用封装在引擎盖下?
Future#序列应该并行执行HTTP请求吗?
首先,Future#sequence
不执行任何内容。它只是在所有参数完成时产生一个完成的未来。如果EC中有空闲线程,则立即开始对构建的未来进行评估(执行(。否则,它只需将其提交给某种队列。我确信,在第一种情况下,您有期货的单线程执行。
println(scala.concurrent.ExecutionContext.Implicits.global(->平行度=6
不知道为什么会这样,可能是其他5个线程由于某种原因总是很忙。您可以尝试使用5-10个线程显式创建的新EC。
与异步情况的不同之处在于,您不会自己创建未来,它是由库提供的,在内部不会阻塞线程。它启动异步进程;订阅";对于结果,并返回future,future在结果出现时完成。
事实上,async lib内部可能会有另一个EC,但我对此表示怀疑。
顺便说一句,如果没有blocking
,Futures不应该包含慢速/io/阻塞评估。否则,您可能会阻塞主线程池(EC(,您的应用程序将被完全冻结。