关于coroutine的异常捕获和取消机制

https://www.youtube.com/watch?v=VWlwkqmTLHc&list=PLQkwcJG4YTCQcFEPuYGuv54nYai_lwil_&index=11

协程总结

抓不到的异常

如果我们在launch外面try catch 意图捕获异常的话

   //无法捕获异常导致奔溃
    private fun cannotCatchException() {
        lifecycleScope.launch {
            try {
                //外面catch不到的
                launch {
                    //只能在这里面try catch,直接捕获
                    throw Exception()
                }

            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

如果不是在抛出异常的地方直接捕获异常,那么在外面是捕获不到的,会直接导致应用奔溃

asyn不会奔溃

如果async中发生了异常,如果没有调用await,则程序不会奔溃

 private fun asyncWonCrash() {
        lifecycleScope.async {
            val string = async {
                delay(1000)
                throw Exception("error")
            }
        }
    }

我们在async中直接抛出异常,但是应用没有奔溃

但如果在launch中运行,需要再await的地方添加捕获,不然程序奔溃

  private fun asyncWonCrash() {
        val result = lifecycleScope.async {
            val string = async {
                delay(1000)
                throw Exception("error")
                "result"
            }
            println("linlian"+string.await())
        }

        lifecycleScope.launch {
            try {
                result.await()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

当时如果只是看到这里,以为就结束了!!!!

no,上面的这个异常捕获,有一个很大的陷阱,之前的文章也有提到

就是我们可能吧 cancellation exception也捕获了,导致协程任务无法取消!!!!

那一般是怎么处理了,可以根coroutinescope添加coroutineexception handler

    private val exceptionHander = CoroutineExceptionHandler { ctx, throwale ->

        println("handle exception $throwale")
    }

    private fun exceptionHandlerdemo() {
        lifecycleScope.launch(exceptionHander) {
            launch {
                throw Exception("error")
            }
        }
    }

这样内部子任务的异常都可以被捕获

协程的某个子任务异常了,那其他的任务会怎样呢?

那这个和所在的scope的类型有关,如果是个普通的sceop

当有一个子协程异常了,其他的协程也取消了

 private fun differentScope() {
        CoroutineScope(Dispatchers.Main).launch(exceptionHander) {
            launch {
                delay(300)
                throw Exception("linlian 1 failed")
            }
            launch {
                delay(500)
                println("linlian 2 success")
            }

        }
    }

但是像viewmodescope这些,还有globalscope,一般我们一个子协程异常,是不会影响到其他的协程的,这个是什么原因呢

viewmodel的源码中

val ViewModel.viewModelScope: CoroutineScope
        get() {
            val scope: CoroutineScope? = this.getTag(JOB_KEY)
            if (scope != null) {
                return scope
            }
            return setTagIfAbsent(JOB_KEY,
                CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate))
        }
SupervisorJob()

Creates a supervisor job object in an active state. Children of a supervisor job can fail independently of each other.

互不影响


    private fun differentScope() {
        CoroutineScope( Dispatchers.Main).launch(exceptionHander) {
            supervisorScope {
                launch {
                    delay(300)
                    throw Exception("linlian 1 failed")
                }
                launch {
                    delay(500)
                    println("linlian 2 success")
                }

            }
            
        }
    }

所以加上 supervisorScope ,任务2就不会因为任务1的异常而被影响,取消了。

另外如果cancellation exception被捕获的话,任务也不会取消,会一直运行下去

<think>首先,用户的问题是“请使用中文回答问题”,但随后是“Coroutine continue failure”。这看起来像是一个错误信息或一个主题。用户可能在问关于协程(coroutine)中的“continue failure”问题。 用户消息的最后部分是“Coroutine continue failure”,这似乎是主题。用户可能想了解协程中出现的“continue failure”错误,或者如何解决它。 用户指定了回答的格式:我必须用中文回答,然后在末尾提出3-5个相关问题,第一行必须是“§§相关问题§§”,并且相关问题必须输出在回答的末尾,不能换行分散。 示例格式是关于快速排序的,包括代码解释,然后相关问题。 所以,对于“Coroutine continue failure”,我需要提供一个解释,可能包括代码示例,然后提出相关问题。 “Coroutine continue failure”可能指的是在协程编程中,协程无法继续执行时出现的错误。例如,在Python的asyncio中,协程可能因为异常或其他原因而失败。 我需要用中文回答。所以,我的回答应该用中文。 结构: 1. 先解释“Coroutine continue failure”是什么。 2. 可能提供示例代码。 3. 然后,在末尾,输出“§§相关问题§§”,并列出3-5个相关问题。 相关问题应该基于我的回答用户的问题。用户的问题是“Coroutine continue failure”,所以我应该提出相关的问题,比如如何避免、调试等。 确保输出格式正确: - 回答完问题后,必须输出“§§相关问题§§”在第一行。 - 然后列出问题,用数字列表,如“1. ···”等。 - 不能换行分散,意思是问题应该紧凑列出。 现在,构建回答: - 解释:协程中的“continue failure”通常意味着协程在等待或执行时遇到了错误,无法继续。这可能由于异常取消或其他异步问题。 - 示例:在Python asyncio中,协程可能抛出异常,导致失败。 - 提供代码示例:比如一个简单的协程函数,模拟失败。 用中文写。 回答大纲: 1. 介绍协程“continue failure”。 2. 解释原因。 3. 给出代码示例。 4. 结束回答。 5. 然后输出“§§相关问题§§”列表。 相关问题想法: 1. 如何调试协程中的失败? 2. 协程失败时如何优雅地处理异常? 3. 在异步编程中,如何避免协程死锁或失败? 4. 协程取消时会发生什么? 5. 不同编程语言中的协程实现有何差异? 确保3-5个。 最终输出: - 回答部分。 - 然后“§§相关问题§§” - 然后1. ... 2. ... 3. ...</think>### 协程中的“continue failure”解释 在异步编程中,“coroutine continue failure”(协程继续失败)指的是协程在执行过程中因异常取消或其他错误而无法正常继续执行的状态。这常见于如 Python 的 asyncio 框架中,协程可能因未处理的异常、超时或资源不足而中断。协程是一种轻量级线程,用于非阻塞 I/O 操作,但当其状态机无法推进时,就会触发此类失败。 **主要原因包括**: - **未捕获异常**:协程内部抛出错误但未用 `try-except` 处理。 - **取消操作**:外部调用 `cancel()` 方法强制终止协程。 - **死锁或资源竞争**:多个协程相互等待导致僵局。 - **超时**:等待操作(如 `asyncio.sleep()` 或 I/O)超时后未恢复。 **示例代码(Python asyncio)**: 以下代码展示了一个可能引发“continue failure”的简单协程。当协程遇到除以零错误时,如果没有异常处理,它会失败并中断执行。 ```python import asyncio async def faulty_coroutine(): try: # 模拟正常操作 await asyncio.sleep(1) # 故意引发错误 result = 1 / 0 # 除以零异常 print(result) except ZeroDivisionError: print("捕获异常,避免失败") except Exception as e: print(f"其他错误: {e}") async def main(): task = asyncio.create_task(faulty_coroutine()) await task asyncio.run(main()) ``` 如果移除 `try-except` 块,此协程会因未处理异常而失败。调试时,可使用 `asyncio.get_event_loop().set_exception_handler()` 来全局处理错误。 **如何避免**: - 使用 `try-except` 捕获协程内部异常。 - 设置超时机制,如 `asyncio.wait_for()` 限制等待时间。 - 确保资源管理(如使用 `async with` 上下文)。 - 监控协程状态,通过 `task.done()` 检查完成情况。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值