Когда вы генерируете исключение в области сопрограмм, можно ли повторно использовать область сопрограмм? - PullRequest
0 голосов
/ 30 ноября 2018

У меня возникли проблемы с вычислением обработки ошибок с сопрограммами, которые я сузил до этого модульного теста с помощью следующих шагов:

  1. Я создаю область сопрограмм с любым диспетчером.
  2. Я выкидываю исключение в любом месте этой области в асинхронном блоке (или даже во вложенном асинхронном блоке).
  3. Я вызываю await для возвращенного отложенного значения и обрабатываю исключение.
  4. Все в порядке.Однако когда я пытаюсь использовать одну и ту же область сопрограмм для запуска новой сопрограммы, она всегда завершается исключительно с тем же исключением.

    Вот тест:

    fun `when you throw an exception in a coroutine scope, is the coroutine scope dead?`() {
        val parentJob = Job()
        val coroutineScope = CoroutineScope(parentJob + Dispatchers.Default)
    
        val deferredResult = coroutineScope.async { throw IllegalStateException() }
    
        runBlocking {
            try {
                deferredResult.await()
            } catch (e: IllegalStateException) {
                println("We caught the exception. Good.")
            }
    
            try {
                coroutineScope.async { println("we can still use the scope") }.await()
            } catch (e: IllegalStateException) {
                println("Why is this same exception still being thrown?")
            }
    
        }
    
    }
    

Вот результат теста:

We caught the exception. Good.
Why is this same exception still being thrown?
  • Почему это происходит?

    • Насколько я понимаю, вымог нормально обрабатывать исключения и восстанавливаться после них с сопрограммами.
  • Как мне обращаться с исключениями?

    • Должен ли янужно создать новый coroutineScope?
    • Могу ли я никогда не генерировать исключения, если я хочу продолжать использовать тот же coroutineScope?
    • Должен ли я вернуть Either<Result, Exception>?
    • Я пытался использовать CoroutineExceptionHandler, но все равно получаю те же результаты.

Примечание. Я использую Kotlin 1.3

1 Ответ

0 голосов
/ 30 ноября 2018

Когда вы запускаете сопрограмму в области (используя async или launch), сбой сопрограммы по умолчанию отменяет эту область, чтобы немедленно отменить все другие дочерние элементы.Такой дизайн позволяет избежать висячих и потерянных исключений.

Общий совет:

  • Не используйте async / await, если только вам действительно не нужен параллелизм.Когда вы разрабатываете свой код с функциями приостановки, нет необходимости использовать async и await.

  • Если вам нужно параллельное выполнение, следуйте шаблону:

    coroutineScope { 
        val d1 = async { doOne() }
        val d2 = async { doTwo() }
        ...
        // retrieve and process results
        process(d1.await(), d2.await(), .... )
    }
    

Если вам нужно обработать сбой параллельной операции, затем поместите try { ... } catch { ... } вокруг coroutineScope { ... }, чтобы поймать сбой в любой из одновременно выполняемых операций.

  • Существуют дополнительные расширенные механизмы (например, SupervisorJob), которые позволяют детализировать обработку исключений.Вы можете прочитать больше в документации https://kotlinlang.org/docs/reference/coroutines/exception-handling.html
...