协程学习笔记1
一、CPU密集型任务Test fun test Cpu Task()runBlocking{ val startTime System.currentTimeMillis() val joblaunch(Dispatchers.Default){ var nextTimestartTime var i0 while (i5){ if(System.currentTimeMillis()nextTime){ println(job:Im sleeping ${i}) nextTime500 } } } delay(1000) println(Im going to cancel) job.cancelAndJoin() }执行结果job:Im sleeping 0 job:Im sleeping 1 job:Im sleeping 2 Im going to cancel job:Im sleeping 3 job:Im sleeping 4任务没有被正常取消处理方式有三种while (i5 isActive)添加isActivewhile (i5){ ensureActive() if(System.currentTimeMillis()nextTime){ println(job:Im sleeping ${i}) nextTime500 } }添加ensureActive()while (i5){ yield() if(System.currentTimeMillis()nextTime){ println(job:Im sleeping ${i}) nextTime500 } }添加yield()二、协程取消资源释放Test fun test cancel and release()runBlocking { val joblaunch{ try { repeat(1000){i- println(task:${i}) delay(200) } }finally { println(job:Im going to release) } } delay(500) println(Im going to cancel) job.cancelAndJoin() }在finally中进行资源的释放当协程的取消过程中有挂起函数要执行时挂起函数无法执行挂起函数之后的代码也不会执行Test fun test cancel and release()runBlocking { val joblaunch{ try { repeat(1000){i- println(task:${i}) delay(200) } }finally { println(job:Im going to release) delay(1000) println(Release completed) } } delay(500) println(Im going to cancel) job.cancelAndJoin() }执行结果task:0 task:1 task:2 Im going to cancel job:Im going to releasedelay挂起函数和后序的println没有执行Test fun test cancel and release()runBlocking { val joblaunch{ try { repeat(1000){i- println(task:${i}) delay(200) } }finally { withContext(NonCancellable){ println(job:Im going to release) delay(1000) println(Release completed) } } } delay(500) println(Im going to cancel) job.cancelAndJoin() }用withContext(NonCancellable)可以解决这个问题task:0 task:1 task:2 Im going to cancel job:Im going to release Release completed三、协程中的异常处理异常传播协程构建器有两种形式自动传播异常launch与actor向用户暴露异常async与produce当这些构建器用于创建一个根协程时前者的异常会在发生的第一时间被抛出而后者依赖用户来最终消费异常例如通过await或receive。非根协程中产生的协程会被传播。当一个协程由于一个异常而运行失败时它会传播这这个异常并传递给它的父级。接下来父级会进行下面几个操作1、取消它自己的子级2、取消它自己3、将异常传播并传递给它的父级SupervisorJob使用SupervisorJob时一个子协程的运行失败不会影响到其他子协程。SupervisorJob不会传播异常给它的父级它会让子协程自己处理异常。//使用SupervisorJob() Test fun text SupervisorJob()runBlocking{ val supervisorJob CoroutineScope(SupervisorJob() Dispatchers.Default) val job1supervisorJob.launch { delay(100) println(child 1) throw IllegalArgumentException() } val job2supervisorJob.launch { delay(1000) println(child 2) } delay(5000) }运行结果child 1和child 2都被打印出来。若将SupervisorJob()改为Job()则只会输出child 1。也可以使用supersScope来达到相同效果。异常的捕获使用CoroutinExceptionHandler对协程的异常进行捕获。以下条件被满足时异常就会被捕获时机异常是被自动抛出异常的协程所抛出的使用launch而不是async位置在CoroutineScope的CoroutineContext中CoroutineScope(Dispatchers.IO handler)在根协程上GlobalScope.launch(handler) CoroutineScope().launch(handler)在supervisorScope的直接子协程中不能给supervisorScope本身设置supervisorScope { launch(handler) { //代码块 } }全局异常处理全局异常处理器可以获取到所有协程(非协程中的不会被捕获)未处理的未捕获的异常不过它并不能对异常进行捕获虽然不能阻止程序崩溃全局异常处理器在程序调试和异常上报等场景中仍然有非常大的用处。我们需要在classpath下面创建META-INF/services目录并在其中创建一个名为kotlinx.coroutines.CoroutineExceptionHandler的文件文件内容就是我们的全局异常处理器的全类名。红色方框里面的复制到kotlinx.coroutines.CoroutineExceptionHandler这个文件中异常的处理如果一个协程遇到了CancellationException以外的异常它将使用该异常取消它的父协程。当父协程取消所有子协程后异常才会被父协程处理。fun test child cancel()runBlocking { val handler CoroutineExceptionHandler{_,exception- println(Caught $exception)//A父协程处理异常 } val job GlobalScope.launch(handler){ launch { try { delay(2000) }finally { withContext(NonCancellable){//B正常的子协程被取消 println(Another coroutine is cancelled) delay(3000) println(finished noncancellable block) } } } launch{ delay(100) println(second child throws an exception) throw IndexOutOfBoundsException()//C异常的子协程出现异常 } } job.join() }运行结果执行顺序为C-B-A(子协程出现异常-取消所有子协程-父协程处理异常)second child throws an exception Another coroutine is cancelled finished noncancellable block Caught java.lang.IndexOutOfBoundsException异常的聚合当协程的多个子协程因为异常而失败时一般情况下取第一个异常进行处理。在第一个异常之后发生的所有其他异常都将被绑定到第一个异常之上。Test fun test compain exception()runBlocking { val handler CoroutineExceptionHandler{_,exception- println(First exception : $exception) println(Later exception : ${exception.suppressedExceptions.toString()}) } val job GlobalScope.launch(handler){ launch{ delay(100) throw IndexOutOfBoundsException() //第一个异常 } launch { try { delay(1000) }finally { withContext(NonCancellable){ throw IllegalArgumentException() //第二个异常 } } } launch { try { delay(2000) }finally { withContext(NonCancellable){ throw IOException() //第三个异常 } } } } job.join() }运行结果First exception : java.lang.IndexOutOfBoundsException Later exception : [java.io.IOException, java.lang.IllegalArgumentException]
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2423433.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!