协程的取消 CPU密集型任务取消

一:协程的取消

1.取消协程作用域CoroutineScope/coroutineScope 会取消它里面的所有子协程       



  coroutineScope  与 CoroutineScope 的区别
  不同点:
  coroutineScope是协程的作用域构建器函数   参数需要传入一个匿名CoroutineScope对象 CoroutineScope的一个函数方法
  CoroutineScope 自己创建了一个协程作用域对象
相同点:
    在里面都可以通过lanuch asynic 创建启动子协程  取消子协程
 
 

 private fun cancelAllSubCoroutine() {
         runBlocking <Unit>{
             /**  suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R
              *    是协程的作用域构建器函数   参数需要传入一个匿名CoroutineScope对象
              *   是 CoroutineScope的一个函数方法
              * */

               coroutineScope({
                 val  job0    =   launch {   LogUtil.e("job0 was executed.") }
                 val  job00   =   async {    LogUtil.e("job00 was executed.") }
                 job0.cancel() //输出  job00 was executed.
             })



/**
 * CoroutineScope(context: CoroutineContext): CoroutineScope
 *  自己创建了一个协程作用域对象
 * */
       //取消协程作用域CoroutineScope会取消它关联的所有子协程job1  job11
             val coroutineScope1  = CoroutineScope(Dispatchers.Default)
             val job1=  coroutineScope1.launch {
                 delay(1000)
                 LogUtil.e("job1 was executed.")
                }

            val job11= coroutineScope1.launch {
                 delay(1000)
                 LogUtil.e("job11 was executed.")
             }

             val coroutineScope2  = CoroutineScope(Dispatchers.Default)
             val job2 =   coroutineScope2.launch {
                 delay(1000)
                 LogUtil.e("job2 was executed.")
             }

             delay(100)
             coroutineScope1.cancel()
             delay(1000)
            //这里是取消协程作用域coroutineScope1,会取消它关联的所有子协程job1 job11   输出最总结果:  job2 was executed.
         }
    }

2.被取消的子协程并不会影响其余兄弟协程
 

   

//协程job1的取消不会影响job11协程的执行    
 private fun cancelOneSubCoroutine() {
        runBlocking <Unit>{
            coroutineScope({
                val job1 =   launch {
                    delay(1000)
                    LogUtil.e("job1 was executed.")
                }

                val job11=  launch {
                    delay(1000)
                    LogUtil.e("job11 was executed.")
                }

                delay(100)
                job1.cancel()
                delay(1000)
                //   输出最总结果:  job11 was executed.

            })

        }
    }

3.取消异常

 协程通过抛出一个特殊的异常 CancellationException 来处理取消操作。

所有kotlinx.coroutines中的挂起函数(withContext、delay等)都是可取消的。

在调用 cancel()函数取消协程时, 可以传入一个 CancellationException 实例来提供更多关于本次取消的详细信息

如果您不构建新的 CancellationException 实例将其作为参数传入的话,会创建一个默认的 CancellationException
 private fun   cancellationException(){
         runBlocking <Unit>{
               /**
                *  GlobalScope 创建协程对象   继承   CoroutineScope
                * */
           val job3   =  GlobalScope.launch {
              try{ delay(1000)
               LogUtil.e("job3 was executed.")
               } catch (e: Exception) {
                   e.printStackTrace()
                  LogUtil.e("job3 cancel exception .${e.toString()}") //输出 job3 cancel exception .java.util.concurrent.CancellationException: 取消协程job3的执行
              }
              }

             delay(100)
             //在调用 cancel()函数取消协程时, 可以传入一个 CancellationException 实例来提供更多关于本次取消的详细信息
             //如果您不构建新的 CancellationException 实例将其作为参数传入的话,会创建一个默认的 CancellationException
             job3.cancel(CancellationException("取消协程job3的执行"))
             job3.join() //协程取消了  无法输出 job3 was executed


         }

    }

  

二:CPU密集型任务取消协程

 

 1.CPU密集型任务取消协程
isActive是一个可以被使用在CoroutineScope中的扩展属性,检查Job是否处于活跃状态。
如果Job 调用cancelAndJoin()函数 取消协程的执行,那么isActive=false ,协程就非活跃状态不执行退出了

2.ensureActive(),如果job处于非活跃状态,

这个方法会立即抛出异常CancellationException,退出协程的执行

ensureActive()查看源码就是isActive: Boolean属性

public fun Job.ensureActive(): Unit {
if (!isActive) throw getCancellationException()
}

 
3.yield

yield()函数会检查当前所在协程的状态,如果该协程(job.cancelAndJoin())已经取消,则抛出异常CancellationException予以响应。

 此外,它还会尝试出让线程的执行权,给其他协程提供执行机会。

 如果要处理的任务属于:
  1) CPU 密集型,
  2) 可能会耗尽线程池资源,
  3) 需要在不向线程池中添加更多线程的前提下允许线程处理其他任务,那么请使用 yield()。

  runBlocking {
            val startTime = System.currentTimeMillis()
            val job = launch(Dispatchers.Default){
                var nextPrintTime = startTime
                var i = 0
                while(i < 10){
                    yield()
                    if(System.currentTimeMillis() >= nextPrintTime){
                        LogUtil.e("job: I'm sleeping ${i++} ...")
                        nextPrintTime += 500L
                    }
                }
            }
            delay(1300L)
            LogUtil.e("main: I'm tired of waiting!")
             job.cancelAndJoin()
            LogUtil.e("main: Now I can quit.")
        }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值