我有以下代码:
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,同样的解决方案会起作用吗?
答案 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并使用预配置的并发策略将其提供给客户端代码)。当然,您可以使用其他方法实现这一目标,但这对我来说看起来更自然。