我正在尝试实现非IO阻塞协程(kotlin),它将获得比线程更多的网络调用。很清楚如何以不阻塞主线程的方式使用协程,但最终每个协程都在一个线程中运行,网络调用会阻塞该线程(相比之下,使用NodeJS可以在其他请求等待响应时重用工作线程)。
我的用例是,对于每个传入的请求,我需要进行2-3次独立的外部调用,聚合响应并返回。按顺序做是浪费时间。并行地执行这项操作将需要我的服务运行大约2-3倍于传入线程数的线程(仅用于等待IO的线程数就达到了大约1K)。
许多程序的例子都使用delay
,这样就可以同时为多个程序重用线程。然而,通过实际使用网络呼叫的真实用例,我无法实现这一点。
我错过了什么?如何暂停协同程序,直到外部服务响应?
例如,这个例子只在5个线程上运行,但在1000次调用中重复使用线程,所以它都在约100ms内结束(每个dealy为100ms)
val myPool = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
runBlocking {
(1..1000).forEach {
launch(myPool) {
delay(100)
}
}
}
与此相反,它实际上只在5个线程上运行5个并发调用,并且只完成一次就可以继续到下一个线程我希望所有调用都"并行"执行,利用在等待响应时发送请求的优势-就像在NodeJS中所做的那样:
val restTemplate = RestTemplate()
val myPool = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
runBlocking {
(1..1000).forEach {
launch(myPool) {
restTemplate.getForObject("http://myTest.com", String::class.java) // Say it takes 100ms to response
}
}
}
Kotlin协程并不是将阻塞网络操作变成非阻塞的魔法。它们只允许您使用异步网络实现,而不需要期货和回调。
因此,为了继续,
- 步骤1。查找异步REST库
- 步骤2。编写一些Kotlin代码,将库的基于本地回调或基于未来的API桥接到Kotlin协程
"我希望执行所有调用";并行地"&";!!
为什么不删除Executor.newFixedThreadPool(5)并给出Dispatchers呢。IO自己管理的郊游?
runBlocking {
(1..1000).forEach {
launch(Dispatchers.IO) {
delay(100)
}
}
}