Котлин параллельные сопрограммы

Допустимо ли сохранять несколько экземпляров заданий из отдельных сопрограмм. Допустим, я хочу запустить пару сопрограмм одновременно, в которых они не связаны и не могут происходить в одной сопрограмме, но я хочу, чтобы они работали параллельно. В 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 ответа

Решение

Вы можете вручную хранить список 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

Это вполне выполнимо, и ничего особенного. Посмотрите на этот простой пример, который создает 100 тыс. Заданий одновременно:

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
}
Другие вопросы по тегам