为什么在协程作用域和简单的挂起函数(Kotlin)中,try/catch的行为不同?

huangapple go评论65阅读模式
英文:

Why try/catch behavior is different in a coroutine scope and in a simple suspending function (Kotlin)?

问题

在尝试管理在协程上重新抛出异常时,我最终理解到在挂起函数中我们可以像通常一样使用try/catch(感谢 @Tenfour04)。

fun main(): Unit = runBlocking {
    launch {
   		doAction()
    }

    launch {
        delay(2000)
        println("Printed2")
    }
}

suspend fun doAction() {
     try {
        delay(1000)
        throw Error("Some error")
    } catch (e: Throwable) { // 不,这里不起作用
        println("Printed1")
    }
}
// Printed1
// Printed2

但困扰我的是(并使我不当地使用了CoroutineExceptionHandler),在以下代码中,try/catch不像通常那样起作用,因为异常会终止协程:

fun main(): Unit = runBlocking {
    // 不要在这里包裹try-catch。它将被忽略。
    try {
        launch {
            delay(1000)
            throw Error("Some error")
        }
    } catch (e: Throwable) { // 不,这里不起作用
        println("不会被打印")
    }

    launch {
        delay(2000)
        println("不会被打印")
    }
}
// Exception in thread "main" java.lang.Error: Some error...

在这两种情况下,我们都处于协程上下文中。区别在于:

  • 第一个没有协程作用域
  • 第二个有协程作用域

我不太清楚为什么在这两种情况下try/catch的行为不同。

英文:

As I tried to managed the rethrow in a coroutine context, I finally understood that in suspending function we can use try/catch as usual (thanks @Tenfour04).

fun main(): Unit = runBlocking {
    launch {
   		doAction()
    }

    launch {
        delay(2000)
        println("Printed2")
    }
}

suspend fun doAction() {
     try {
        delay(1000)
        throw Error("Some error")
    } catch (e: Throwable) { // nope, does not help here
        println("Printed1")
    }
}
// Printed1
// Printed2

But what was confusing me (and make me use badly the CoroutineExceptionHandler) is in the following code the try/catch is not working as usual, as the exception kills the coroutine :

fun main(): Unit = runBlocking {
    // Don't wrap in a try-catch here. It will be ignored.
    try {
        launch {
            delay(1000)
            throw Error("Some error")
        }
    } catch (e: Throwable) { // nope, does not help here
        println("Will not be printed")
    }

    launch {
        delay(2000)
        println("Will not be printed")
    }
}
// Exception in thread "main" java.lang.Error: Some error...

In both case, we are in a coroutine context. The difference is :

  • the first one has not a coroutine scope as this
  • the second one as coroutine scope as this

I'm not very clear of why the try/catch behavior is different in the both cases

答案1

得分: 0

我明白了。这是因为try/catch在协程之外。如果我更改try/catch和launch,异常不会终止协程。

import kotlinx.coroutines.*
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    // 不要在这里包装try-catch。它会被忽略。
    launch {
    	try {
            delay(1000)
            throw Error("Some error")
        } catch (e: Throwable) { // 不,这里不起作用
            println("不会被打印出来")
        }
    }

    launch {
        delay(2000)
        println("不会被打印出来")
    }
}

抱歉,这很明显。

Tenfour04在之前的问题中告诉了我,但我没有明白。

Stackoverflow是一个好的心灵疗法 为什么在协程作用域和简单的挂起函数(Kotlin)中,try/catch的行为不同?

英文:

Ok I understood. This is because the try/catch is outside of coroutine. If I change the try/catch and the launch, the exception not kill the coroutine.

import kotlinx.coroutines.*
import kotlinx.coroutines.runBlocking

fun main(): Unit = runBlocking {
    // Don't wrap in a try-catch here. It will be ignored.
    launch {
    	try {
            delay(1000)
            throw Error("Some error")
        } catch (e: Throwable) { // nope, does not help here
            println("Will not be printed")
        }
    }

    launch {
        delay(2000)
        println("Will not be printed")
    }
}

Sorry, it was so evident.

Tenfour04 told me in the previous question, but I did’t get that.

Stackoverflow is a good therapy 为什么在协程作用域和简单的挂起函数(Kotlin)中,try/catch的行为不同?

huangapple
  • 本文由 发表于 2023年3月4日 00:17:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75629494.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定