【问题标题】:Kotlin parallel coroutinesKotlin 并行协程
【发布时间】:2023-03-11 14:18:01
【问题描述】:

是否可以从单独的协程中保存多个作业实例。假设我想一次运行几个协程,它们不相关并且不能在一个协程中发生,但我希望它们并行运行。在 Android 中,我应该保存作业实例,以便我可以在 onDestroy 方法中取消作业。将每个工作单独保存在列表中是否可以接受,或者我是否违反了某种规则。我知道在 RX 中他们有订阅,为什么 Kotlin 协程中没有等价的?

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)
}

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

【问题讨论】:

    标签: android kotlin kotlin-coroutines


    【解决方案1】:

    您可以手动保留您启动的Job 对象列表,但您也可以使用开箱即用的父子作业层次结构来更轻松地管理和保留已启动作业的列表。

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

    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()
    }
    

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

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

    【讨论】:

    • 这样您一次仍然只有一份父工作。我的问题是关于有一份父母工作的清单。我什至举了一个我所质疑的例子。
    • 我在答案中提供的代码与您的原始代码完全相同。它仍然运行多个作业,它们仍然保存在一个列表中。尝试一下。不同之处在于您不必显式管理此列表,因为所有作业都是子作业,并且父母会自动保留他们的列表。
    • 有道理,是否可以在 UI 线程上使用 Job() 上下文。
    • 你可以使用launch(UI + job)
    • 在这种方法中有一种方法可以取消特定的协程吗?比如给一个 id 然后取消它?
    【解决方案2】:

    这是完全可行的,也没什么特别的。看看这个一次性创建 10 万个工作的简单示例:

    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
    }
    

    【讨论】:

    • 我知道这是可行的,但它是否正确,协程应该如何使用?在 android 中,我必须处理每个作业的状态,并处理重复作业是否是我想忽略的错误,或者我应该再次运行它
    • 绝对是的。为了使作业可取消,它必须自己检查是否已从外部取消,您可以通过循环活动状态来做到这一点:while (isActive)
    • 您正在从主协程中保存所有子作业并在函数结束时取消。我更担心保存多个父作业,知道何时取消这些作业并确保不存在重复作业。父母将在销毁时取消。 2 个非常不同的东西
    • 对不起,我没听懂你的问题
    猜你喜欢
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 2020-10-07
    • 1970-01-01
    • 2021-02-23
    • 1970-01-01
    • 2019-02-19
    • 1970-01-01
    相关资源
    最近更新 更多