Параллельная декомпозиция независимых асинхронных задач с соплинами Котлина - PullRequest
1 голос
/ 16 октября 2019

Я пытаюсь запустить несколько задач параллельно, но задачи независимы, поэтому, если один из дочерних сопрограмм завершится с ошибкой, я не хочу, чтобы его братья и сестры тоже потерпели неудачу. В приведенном ниже коде я использовал coroutineScope для создания новой области действия, в которой выполняются эти задачи, и запускал 5 асинхронных задач, каждая из которых отправляла свой идентификатор и время задержки, которое он должен ждать. Вторая сопрограмма бросает исключение. В этом случае код выполняет то, что я хочу, он вычисляет сумму успешно завершенных и неудавшихся заданий, возвращающих 0.

Однако я читаю, что в kotlinx также есть supervisorScope. библиотека, которая должна быть предпочтительнее, чем coroutineScope (которая отменяет родительский / родной брат, если исключение не обрабатывается), поскольку задачи не зависят от других. Я не уверен, почему мне следует перейти на использование supervisorScope, поскольку я получаю нужный результат с помощью coroutineScope.

Q1 : Если я перехожу на supervisorScope, в моем асинхронном случае что-то изменитсяblocks?

Q2 : Принято ли перехватывать какие-либо исключения внутри асинхронного блока и не позволять что-либо распространяться на его родительский элемент? Я знаю, что вы также можете перехватывать исключения во время фазы .await (), но так ли это должно быть?

runBlocking {
    coroutineScope {
            val job1 = async<Int> {
                try {
                    request(1, 1000)
                } catch (e: Exception) {
                    println("Job 1 failed with $e")
                    0
                }
            }

            val job2 = async<Int> {
                try {
                    request(2, 2000)
                    throw Exception("cancelling Job 2")
                } catch (e: Exception) {
                    println("Job 2 failed: $e")
                    0
                }
            }

            val job3 = async {
                try {
                    request(3, 3000)
                } catch (e: Exception) {
                    println("Job 3 failed with $e")
                    0
                }
            }

            val job4 = async {
                try {
                    request(4, 4000)
                } catch (e: Exception) {
                    println("Job 4 failed with $e")
                    0
                }
            }

            val job5 = async {
                try {
                    request(5, 5000)
                } catch (e: Exception) {
                    println("Job 5 failed with $e")
                    0
                }
            }

            val result = job1.await() + job2.await() + job3.await() + job4.await() + job5.await()
            println(result.toString())
        }

        println("Finished")
}

suspend fun request(id: Int, time: Long): Int {
    println("Job $id started")
    delay(time)
    println("Job $id finished")
    return id
}

1 Ответ

1 голос
/ 16 октября 2019

Причина, по которой все сопрограммы выполняются до завершения, заключается в том, что вы catch исключение, выдаваемое заданием 2 в самом задании 2, поэтому оно никогда не распространяется по иерархии Job с, поэтому ничего не происходит.

Однако, если вы удалите это условие catch в job2, задание [1-5] всегда будет отменено, независимо от того, используете ли вы coroutineScope или supervisorScope.

Это потому, что job2.await() будетбросить исключение вместоПоскольку это происходит в родительском задании задания [1-5] (т. Е. В верхнем coroutineScope / supervisorScope), и так как неудачное / отмененное родительское задание всегда отменяет дочерние задания, задание [1-5] также будетотменено.

A1 : не используйте ни один из coroutineScope или supervisorScope, удалите coroutineScope и поместите вещи прямо под runBlocking.

A2: Разумеется, разрешено перехватывать исключения в пределах async { }, чтобы быть уверенным, что это не произойдет в .await(), если это соответствует вашему сценарию использования.

...