Kotlin并行协程

时间:2017-11-10 20:05:42

标签: android kotlin kotlin-coroutines

从单独的协程中保存多个作业实例是否可以接受。让我们说我想要同时运行几个协同程序,它们是无关的,不能在一个协同程序中发生,但我希望它们并行运行。在Android中我应该保存作业实例,以便我可以在onDestroy方法中取消作业。将每个工作单独保存在列表中还是打破某种规则是可以接受的。我知道在RX他们有订阅为什么在Kotlin Coroutines中没有相应的东西?

val jobList = arrayListOf<Job>()

fun startJob1() {
    jobList.add(launch {
        //do some work
    })

fun startJob1() {
    jobList.add(launch {
        //do some other unrelated work
    })

override fun onDestroy() {
    super.onDestroy()
    cancelAllActiveJobs(jobList)
}

这种架构对协同程序有意义吗?

2 个答案:

答案 0 :(得分:4)

您可以手动保留已启动的Job个对象的列表,但您也可以使用开箱即用的父子Job Hierarhy来管理并保持已启动作业的列表更轻松

因此,首先,您要定义对父作业的引用,而不是作业列表:

val job = Job()

然后,每当你找到一个新的协程时,你就会成为这个职位的孩子

fun startJob1() {
    launch(job) { // make it a child
        //do some work
    }
}

fun startJob1() {
    launch(job) { // make it a child
        //do some other unrelated work
    }
}

最后,当您需要销毁对象并取消所有作业时,您只需取消父作业。

override fun onDestroy() {
    super.onDestroy()
    job.cancel()
}

此apporoach的优点是自动管理作业列表。可以启动新的协同程序并将其添加到父作业中,当它们完成时,它们会自动从父作业中删除它们。

您可以在指南的相应部分阅读更多内容:https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#cancellation-via-explicit-job

答案 1 :(得分:3)

这完全可行,也没什么特别的。看看这个简单的例子,它可以同时创建100k个工作:

val jobs = List(100_000) { // launch a lot of coroutines and list their jobs
        launch {
            delay(1000L)
            print(".")
        }
    }
 jobs.forEach { it.join() } 

为了使作业可以取消,它必须自己检查它是否已从外部取消,你可以通过活动状态循环来完成:while (isActive)

以下是一个示例,其中包含两个后续取消的作业:

fun main(args: Array<String>) = runBlocking {
    val startTime = System.currentTimeMillis()
    val jobs = arrayListOf<Job>()
    jobs += launch {
        var nextPrintTime = startTime
        var i = 0
        while (isActive) { // check if still active
            if (System.currentTimeMillis() >= nextPrintTime) {
                println("Job1: Sleeping ${i++} ...")
                nextPrintTime += 500L
            }
        }
    }

    //another job
    jobs += launch {
        while (isActive) { // check if still active
            if (System.currentTimeMillis() >= 42) {
                println("Job2: Sleeping 42 ...")
                delay(500L)
            }
        }
    }
    delay(1300L) // delay a bit
    println("main: Cancelling the sleeping job!")
    jobs.forEach { it.cancelAndJoin() } // cancels the job and waits for its completion
}