我正在将当前的应用程序从Java转换为Kotlin,然后遇到了这个问题。
用于通过线程从服务器传输数据的Java实现。
这将创建大约100个不同的线程来请求数据,但是据我所知,一次最多运行4个线程,其他线程将在启动之前等待线程完成。
将其翻译为Kotlin时,我使用了协程
这造成了一个问题,因为显然服务器无法处理实际发送的100个请求。
所有协程都在相同的范围内启动,所以就像这样:
//this is a custom scope that launches on Dispatchers.IO + a job that I can use to cancel everything
transferScope.launch {
//loadData is a suspending function that returns true/false
val futures = mDownloadJobs.map{ async { it.loadData() } }
val responses = futures.awaitAll()
//check that everything in responses is true etc....
}
有没有一种方法可以使特定的transferScope一次只允许多达5个协程,然后在一个协程完成后再运行另一个协程? (我不在乎订单)
如果无法通过示波器完成操作,是否可以通过其他方式实现?
答案 0 :(得分:1)
在请求之前,要求每个协程从总共5个许可中获取Kotlin Semaphore
许可。
类似这样的东西:
import kotlinx.coroutines.sync.Semaphore
val requestSemaphore = Semaphore(5)
val futures = mDownloadJobs.map {
async {
// Will limit number of concurrent requests to 5
requestSemaphore.withPermit {
it.loadData()
}
}
}
val responses = futures.awaitAll()
答案 1 :(得分:1)
我相信您应该引导并限制正在创建的协程的创建。
val channel = Channel<Job>()
transferScope.launch {
mDownloadJobs.forEach { channel.send(it) }
channel.close() // don't forget to close the channel
}
coroutineScope {
val responses = mutableListOf<Any>()
repeat(5).map {
launch {
for (job in mDownloadJobsChannel) {
responses.add(jobs.loadData())
}
}
}
}
在这种情况下,并行化是5个协程。
我没有测试此代码:D,并且我确定有更干净的方法可以做到这一点。
答案 2 :(得分:0)
您可以执行以下操作,将请求分为4个块,启动协程以对其进行处理,然后等到该组完成后再启动新请求。
requests.chunked(4).forEachIndexed { index, chunk ->
coroutineScope {
LOG("processing chunk $index")
chunk.forEach {
launch {
delay(100)
}
}
LOG("done processing $index")
}
}
答案 3 :(得分:0)
Dispatchers.IO
声称创建一个线程池并限制跨出到该池。它的文档字符串告诉您如何更改池大小(系统属性)。