Kotlin 协程:等待多个线程完成
Kotlin Coroutines : Waiting for multiple threads to finish
所以第一次看协程,我想并行处理一个数据负载并等待它完成。我环顾四周,看到了 RunBlocking 和 Await 等,但不确定如何使用它。
到目前为止我有
val jobs = mutableListOf<Job>()
jobs += GlobalScope.launch { processPages(urls, collection) }
jobs += GlobalScope.launch { processPages(urls, collection2) }
jobs += GlobalScope.launch { processPages(urls, collection3) }
然后我想know/wait完成这些
您可以使用 async
构建器函数并行处理数据负载:
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
}
}
扩展函数asyncIO
:
fun <T> CoroutineScope.asyncIO(ioFun: () -> T) = async(Dispatchers.IO) { ioFun() } // CoroutineDispatcher - runs and schedules coroutines
GlobalScope.launch
is not recommended to use 除非您希望协程在整个应用程序生命周期内运行并且不会过早取消。
编辑:如 Roman Elizarov 所述,您可以尝试不使用 awaitAll()
函数,除非您想更新 UI 或在处理完所有数据后立即执行其他操作。
如果您使用结构化并发的概念,则无需手动跟踪您的并发作业。假设您的 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) }
}
现在,如果您的应用程序的最顶层功能还不是挂起功能,那么您可以使用 runBlocking
调用 processAllPages
:
runBlocking {
processAllPages()
}
可以使用以下方法。
fun myTask() {
GlobalScope.launch {
val task = listOf(
async {
},
async {
}
)
task.awaitAll()
}
}
所以第一次看协程,我想并行处理一个数据负载并等待它完成。我环顾四周,看到了 RunBlocking 和 Await 等,但不确定如何使用它。
到目前为止我有
val jobs = mutableListOf<Job>()
jobs += GlobalScope.launch { processPages(urls, collection) }
jobs += GlobalScope.launch { processPages(urls, collection2) }
jobs += GlobalScope.launch { processPages(urls, collection3) }
然后我想know/wait完成这些
您可以使用 async
构建器函数并行处理数据负载:
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
}
}
扩展函数asyncIO
:
fun <T> CoroutineScope.asyncIO(ioFun: () -> T) = async(Dispatchers.IO) { ioFun() } // CoroutineDispatcher - runs and schedules coroutines
GlobalScope.launch
is not recommended to use 除非您希望协程在整个应用程序生命周期内运行并且不会过早取消。
编辑:如 Roman Elizarov 所述,您可以尝试不使用 awaitAll()
函数,除非您想更新 UI 或在处理完所有数据后立即执行其他操作。
如果您使用结构化并发的概念,则无需手动跟踪您的并发作业。假设您的 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) }
}
现在,如果您的应用程序的最顶层功能还不是挂起功能,那么您可以使用 runBlocking
调用 processAllPages
:
runBlocking {
processAllPages()
}
可以使用以下方法。
fun myTask() {
GlobalScope.launch {
val task = listOf(
async {
},
async {
}
)
task.awaitAll()
}
}