限制可以在示波器中运行的协程最大数量

时间:2019-10-17 08:52:06

标签: android kotlin coroutine

我正在将当前的应用程序从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个协程,然后在一个协程完成后再运行另一个协程? (我不在乎订单)

如果无法通过示波器完成操作,是否可以通过其他方式实现?

4 个答案:

答案 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 声称创建一个线程池并限制跨出到该池。它的文档字符串告诉您如何更改池大小(系统属性)。