【带着问题学】协程异常到底是怎么传播的?

前言

我们需要了解到以下前置知识:
1.协程通过异常处理器来捕获异常
2.协程取消时会抛出CancellationException,需要特别对待
3.协程中存在不同的作用域,不同作用域的异常传播机制不同

看到上面这些前置知识,本文主要内容也就呼之欲出了
1.协程异常处理器是如何生效的?
2.协程取消时的异常如何处理?
3.不同的作用域的异常传播机制不同是怎样实现的?
4.协程异常传播流程图总结

1. 前置知识

本文主要内容是对kotlin协程异常传播的原理介绍,下面先介绍一下前置知识

1.1 异常处理器

kotlin异常处理器即CoroutineExceptionHandler,CoroutineExceptionHandler也继承于CoroutineContext
在创建协程时添加到上下文中,在发生异常时通过key从上下文中获得
我们一般这样使用:

    val handler = CoroutineExceptionHandler { coroutineContext, throwable ->
        println("error")
    }

    viewModelScope.launch(handler) {
        //...
    }

1.2 协程作用域

协程作用域主要用于明确协程之间的父子关系,以及对于取消或者异常处理等方面的传播行为,主要分为以下三类:

  • 顶级作用域:没有父协程的协程所在的作用域为顶级作用域
  • 协同作用域:协程中启动新的协程,新协程为所在协程的子协程,这种情况下子协程所在的作用域默认为协同作用域。此时子协程抛出的未捕获异常都将传递给父协程处理,父协程同时也会被取消。
  • 主从作用域:与协同作用域在协程的父子关系上一致,区别在于处于该作用域下的协程出现未捕获的异常时不会将异常向上传递给父协程

1.3 异常传播机制

协程最创新的功能之一就是结构化并发。为了使结构化并发的所有功能成为可能,CoroutineScopeJob对象以及CoroutinesChild-CoroutinesJob对象形成了父子关系的层次结构。
未捕获的异常会优先向上传播,直到没有父协程才自行处理。这种异常传播会导致父Job的失败,进而导致其子级所有Job的取消。

如上所示,子协程的异常传播到协程(1)的Job,然后传播到topLevelScope(2)的Job

但是如果我们中间使用了supervisorScope,它将截断异常向上传播

2. 异常处理器是如何生效的?

我们一般使用CoroutineExceptionHandler来处理异常,简单示例如下

    fun testExceptionHandler() {
        val handler = CoroutineExceptionHandler { coroutineContext, throwable ->
            print("error")
        }
        viewModelScope.launch(handler) {
            print("1")
  
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[2\]中提到,在Python 3.5中引入了async/await关键字来定义协程函数。协程是一种轻量级的并发编程方式,它可以在一个线程中实现多个任务的并发执行。协程通过使用yield关键字来实现任务的暂停和恢复,从而实现任务之间的切换。而在Python 3.5之前,协程的实现需要使用asyncio.coroutine装饰器和yield from语句。 举个例子来说明协程的使用。在引用\[3\]中的代码中,我们定义了一个名为do_some_work的协程函数,它接受一个name参数和一个t参数。在函数内部,我们使用await关键字来暂停协程的执行,模拟了一些耗时的工作。然后我们使用asyncio.gather函数来同时运行多个协程任务。最后,我们使用事件循环的run_until_complete方法来运行这些协程任务,并获取它们的返回值。 在这个例子中,我们创建了两个协程任务task1和task2,它们分别执行了do_some_work函数。通过调用asyncio.gather函数,我们将这两个任务一起提交给事件循环进行执行。最后,我们通过调用run_until_complete方法来运行这些任务,并获取它们的返回值。在这个例子中,返回值是一个包含了协程函数的返回值的列表。 总结来说,协程是一种轻量级的并发编程方式,它可以在一个线程中实现多个任务的并发执行。在Python中,我们可以使用async/await关键字来定义和使用协程。通过使用事件循环和相关的方法,我们可以实现协程的并发执行,并获取它们的返回值。 #### 引用[.reference_title] - *1* [Python - 协程开发那点事儿](https://blog.csdn.net/qq_38900563/article/details/127168618)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [python 异步编程之协程](https://blog.csdn.net/qq_43745578/article/details/129862804)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值