Kotlin Coroutines : Waiting for multiple threads to finish

Bur*_*000 5 coroutine kotlin kotlin-coroutines

So looking at Coroutines for the first time, I want to process a load of data in parallel and wait for it to finish. I been looking around and seen RunBlocking and Await etc but not sure how to use it.

I so far have

val jobs = mutableListOf<Job>()
jobs += GlobalScope.launch { processPages(urls, collection) }
jobs += GlobalScope.launch { processPages(urls, collection2) }
jobs += GlobalScope.launch { processPages(urls, collection3) }
Run Code Online (Sandbox Code Playgroud)

I then want to know/wait for these to finish

Rom*_*rov 13

如果使用结构化并发概念,则无需手动跟踪并发作业。假设您的processPages函数执行某种阻塞的IO,则可以将代码封装到以下挂起函数中,该函数在为此类工作而设计的IO调度程序中执行代码:

suspend fun processAllPages() = withContext(Dispatchers.IO) { 
    // withContext waits for all children coroutines 
    launch { processPages(urls, collection) }
    launch { processPages(urls, collection2) }
    launch { processPages(urls, collection3) }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果应用程序的最高功能还不是挂起功能,则可以使用runBlocking调用processAllPages

runBlocking {
    processAllPages()
}
Run Code Online (Sandbox Code Playgroud)

  • 这样可以并行运行所有作业吗? (2认同)

Ser*_*gey 11

您可以使用asyncbuilder 函数并行处理数据负载:

class Presenter {
    private var job: Job = Job()
    private var scope = CoroutineScope(Dispatchers.Main + job) // creating the scope to run the coroutine. It consists of Dispatchers.Main (coroutine will run in the Main context) and job to handle the cancellation of the coroutine.

    fun runInParallel() {
        scope.launch { // launch a coroutine
            // runs in parallel
            val deferredList = listOf(
                    scope.asyncIO { processPages(urls, collection) },
                    scope.asyncIO { processPages(urls, collection2) },
                    scope.asyncIO { processPages(urls, collection3) }
            )

            deferredList.awaitAll() // wait for all data to be processed without blocking the UI thread

            // do some stuff after data has been processed, for example update UI
        }
    }

    private fun processPages(...) {...}

    fun cancel() {
        job.cancel() // invoke it to cancel the job when you don't need it to execute. For example when UI changed and you don't need to process data
    }
}
Run Code Online (Sandbox Code Playgroud)

扩展功能asyncIO

fun <T> CoroutineScope.asyncIO(ioFun: () -> T) = async(Dispatchers.IO) { ioFun() } // CoroutineDispatcher - runs and schedules coroutines
Run Code Online (Sandbox Code Playgroud)

GlobalScope.launch 不建议使用,除非您希望协程在整个应用程序生命周期内运行并且不会过早取消。

编辑:正如 Roman Elizarov 所提到的,awaitAll()除非您想更新 UI 或在处理完所有数据后立即执行其他操作,否则您可以尝试不使用函数。

  • 不需要 `async`,因为这里没有使用结果。也不需要执行 `awaitAll`,因为无论如何外部协程都会等待所有子进程。 (2认同)

TN *_*dav 5

可以使用以下方法。

fun myTask() {
    GlobalScope.launch {
        val task = listOf(
            async {

            },
            async {

            }
        )
        task.awaitAll()

    }
}
Run Code Online (Sandbox Code Playgroud)