Kotlin Coroutines - How to block to await/join all jobs?

后端 未结 3 1162
滥情空心
滥情空心 2021-01-18 07:17

I am new to Kotlin/Coroutines, so hopefully I am just missing something/don\'t fully understand how to structure my code for the problem I am trying to solve.

Essen

相关标签:
3条回答
  • 2021-01-18 07:28

    Runblocking should mean you don't have to call join. Launching a coroutine from inside a runblocking scope should do this for you. Have you tried just:

    fun processData(lstInputs: List<String>): List<response> {
    
    val lstOfReturnData = mutableListOf<response>()
    
    runBlocking {
        lstInputs.forEach {
                launch(Dispatchers.IO) {
                    lstOfReturnData.add(networkCallToGetData(it))
                }
       } 
    }
    
    return lstofReturnData
    
    0 讨论(0)
  • 2021-01-18 07:43

    runBlocking blocks current thread interruptibly until its completion. I guess it's not what you want. If I think wrong and you want to block the current thread than you can get rid of coroutine and just make network call in the current thread:

    val lstOfReturnData = mutableListOf<response>()
    lstInputs.forEach {
        lstOfReturnData.add(networkCallToGetData(it))
    } 
    

    But if it is not your intent you can do the following:

    class Presenter(private val uiContext: CoroutineContext = Dispatchers.Main) 
        : CoroutineScope {
    
        // creating local scope for coroutines
        private var job: Job = Job()
        override val coroutineContext: CoroutineContext
            get() = uiContext + job
    
        // call this to cancel job when you don't need it anymore
        fun detach() {
            job.cancel()
        }
    
        fun processData(lstInputs: List<String>) {
    
            launch {
                val deferredList = lstInputs.map { 
                    async(Dispatchers.IO) { networkCallToGetData(it) } // runs in parallel in background thread
                }
                val lstOfReturnData = deferredList.awaitAll() // waiting while all requests are finished without blocking the current thread
    
                // use lstOfReturnData in Main Thread, e.g. update UI
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-18 07:47

    mutableListOf() creates an ArrayList, which is not thread-safe.
    Try using ConcurrentLinkedQueue instead.

    Also, do you use the stable version of Kotlin/Kotlinx.coroutine (not the old experimental one)? In the stable version, with the introduction of structured concurrency, there is no need to write jobs.joinAll anymore. launch is an extesion function of runBlocking which will launch new coroutines in the scope of the runBlocking and the runBlocking scope will automatically wait for all the launched jobs to finsish. So the code above can be shorten to

    val lstOfReturnData = ConcurrentLinkedQueue<response>()
    runBlocking {
            lstInputs.forEach {
                launch(Dispatches.IO) {
                    lstOfReturnData.add(networkCallToGetData(it))
                }
            }
    }
    return lstOfReturnData
    
    0 讨论(0)
提交回复
热议问题