如何使用改造阻止客户端和协同程序实现有限的调用

时间:2017-09-24 18:02:49

标签: kotlin retrofit kotlinx.coroutines

我有以下代码:

val context = newFixedThreadPoolContext(nThreads = 10, name="myThreadPool")
val total = 1_000_000 //can be other number as well
val maxLimit = 1_000
return runBlocking {
  (0..total step maxLimit).map {
    async(context) {
      val offset = it
      val limit = it + maxLimit
      blockingHttpCall(offset, limit)
    }
  }.flatMap {
    it.await()
  }.associateBy {
    ...
  }.toMutableMap()
}

我希望只有10个调用同时发生在阻塞api上。 但是,上面的代码似乎没有像我预期的那样(我认为所有的电话都是立即启动),或者至少我不明白是否这样做。
实施它的正确方法是什么? 如果我使用改造的async api,同样的解决方案会起作用吗?

1 个答案:

答案 0 :(得分:2)

我不确切知道你的情况,但最简单的方法 - 使用OkHttp API来配置并发级别,例如,这是default concurrency strategy of OkHttp

但如果您将自己的Dispatcher实例设置为OkHttpClient.Builder

,则可以拥有自己的策略

当然,您也可以使用协同程序

您当前的实现是不正确的,因为您为每个项目创建了协同程序调度程序,但是要拥有共享的线程池,所有协同程序应该使用相同的调度程序,只需在循环外部创建newFixedThreadPoolContext创建(现在您有1000个)每个调度程序有10个线程。)

但我不建议您使用协程+阻塞调用,更好地配置OkHttp并发(它更灵活)并使用协程与非阻塞调用(您可以编写自己的适配器或使用现有的库,如{{3 }})。它允许您混合您的http请求和UI代码或其他任务。

因此,如果您使用非阻塞API + OkHttp内部并发,则不需要特殊代码来控制并发性,当然,您可以限制并发调用的数量,如上例所示(使用固定调度程序构造) ),但我真的不认为它有多大意义,因为你可以降低并发水平,而不是增加它。

转移到非阻塞API之后,您可以在任何协同程序调度程序中并行运行所有协同程序(即使在UI线程中)并等待结果而不会阻塞。

此外,使用OkHttpClient配置隐式控制并发性在架构方面看起来更正确(您可以使用DI代码配置Retrofit + OkHttp并使用预配置的并发策略将其提供给客户端代码)。当然,您可以使用其他方法实现这一目标,但这对我来说看起来更自然。