💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## 协程的取消需要内部配合 单纯的执行`job.cancel()`是无法取消当前执行的协程,就像无法取消正在执行过程中的线程; ```kotlin fun main() = runBlocking { val job = launch(Dispatchers.Default) { var i = 0 // 变化在这里,只有协程处于活跃状态的时候,才会继续执行循环内部的代码 while (isActive) { Thread.sleep(500L) i++ println("i = $i") } } delay(2000L) job.cancel() job.join() println("End") } ``` ## 不要轻易打破协程的父子结构 下面代码中`firstJob`无法通过`parentJob.cancel`被取消,因为`firstJob`设置了自己的`Job()`对象,并没有关联`parentJob`,打破了其协程的父子结构; ```kotlin fun main2() = runBlocking { val parentJob = launch(Dispatchers.IO) { val firstJob = launch(Job()) { var i = 0 while (isActive) { Thread.sleep(500L) i++ println("First i = ${i}") } } val secondJob = launch { var i = 0 while (isActive) { Thread.sleep(500L) i++ println("Second i = ${i}") } } } delay(2000L) parentJob.cancel() parentJob.join() println("End") Thread.sleep(100_000) } ``` ## 捕获CancellationException以后,要考虑是否应该重新抛出来 ```kotlin fun main() = runBlocking { val parentJob = launch(Dispatchers.IO) { launch() { var i = 0 while (true) { try { delay(500L) } catch (e: CancellationException) { // 这里如果不将CancellationException抛出,那么该协程被取消也不会结束 e.printStackTrace() } i++ println("First i = ${i}") } } launch { var i = 0 while (true) { delay(500L) i++ println("Second i = ${i}") } } } delay(2000L) parentJob.cancel() parentJob.join() println("End") Thread.sleep(100_000) } ``` ## 不要直接使用try-catch直接包裹launch、async 使用`launch`和`async`启动的协程其实已经是一个封闭的任务,任务内部有自己的异常处理逻辑,再外部进行`try-catch`是无法得到响应的内部异常的,只能捕获到创建协程时候的异常; ## 灵活使用SupervisorJob,控制异常传播范围 `SupervisorJob`目前我只觉得只有当前协程抛出异常才能做到不影响子协程和父协程,如果是子协程抛出异常那么`SupervisorJob`也无能为力。因为创建子协程的时候又会创建一个新的`job`只不过其`parentjob`是`父协程的job`。 ## 使用CoroutineExceptionHandler处理复杂结构的协程异常,它仅在顶层协程中起作用