美文网首页Kotlin
组合挂起函数

组合挂起函数

作者: 码农修行之路 | 来源:发表于2020-11-15 22:25 被阅读0次
    组合挂起函数.png

    挂起函数调用顺序

    • 在协程中顺序调用多个挂起函数 这多个挂起函数执行的顺序和常规代码中一样 默认都是顺序执行的
      常规代码中函数调用:
    fun main() {   
        // 例子:普通函数的调用 执行顺序    
      normalOne()    
      normalTwo()
    }
    // 普通函数1
    fun normalOne() {
        Thread.sleep(500L)
       println("普通函数1执行完毕")
    }
    // 普通函数2
    fun normalTwo() {
      Thread.sleep(500L)
      println("普通函数2执行完毕")
    }
    挂起函数调用:
    fun main() = runBlocking {    
      // 例子:如果我们想获取两个挂起函数的总用时    
      val totalTime = measureTimeMillis {        
        doSomethingOne()
        doSomethingTwo()
      }    
      println(" 总耗时:$totalTime ")
    }
    // 挂起函数1
    suspend fun doSomethingOne() {
      delay(1000L)
      println("挂起函数1执行完毕")
    }
    // 挂起函数2
    suspend fun doSomethingTwo() {
      delay(1000L)
      println("挂起函数2执行完毕")
    }
    执行结果:
    挂起函数1执行完毕
    挂起函数2执行完毕
    总耗时:2015
    

    使用async并发

    • 使用场景 如果调用的多个函数 没有之间的相互依赖的关系 无需同步 异步执行更高效更省时
      从概念上讲 async类似于launch async启动一个单独的协程(轻量级) 不同之处是,launch返回job对象并不携带任何运行结果值 而async返回一个轻量级非阻塞的Deferred对象 可用于在最后取出返回值 可以通过调用Deferred的await()方法来获取最终的结果 同时它也实现了Job接口 也可以根据需要去取消它
    fun main() = runBlocking {
      val time = measureTimeMillis {
        val one = async { suspendFunctionOne() }
        val two = async { suspendFunctionTwo() }
        println(" 挂起函数1返回结果 ${one.await()} 挂起函数2返回结果 ${two.await()} ")
      }
      println(" async 并发执行总耗时:$time ")
    }
    // 挂起函数1
    suspend fun suspendFunctionOne(): Int {
      println(" 挂起函数1执行开始 ")
      delay(1000L)
      println(" 挂起函数1执行结束 ")
      return 22
    }
    // 挂起函数2
    suspend fun suspendFunctionTwo(): Int {
      println(" 挂起函数2执行开始 ")
      delay(1000L)
      println(" 挂起函数2执行结束 ")
      return 33
    }
    执行结果返回:
    挂起函数1执行开始  
    挂起函数2执行开始  
    挂起函数1执行结束  
    挂起函数2执行结束  
    挂起函数1返回结果 22 挂起函数2返回结果 33  
    async 并发执行总耗时:1036
    
    1. 运行耗时几乎是减半了,因为这两个协程是同时运行,总的耗时时间可以说是取决于耗时最长的任务。需要注意,协程的并发总是显式的

    惰性启动async

    • 只有在主动调用 Deferred 的 await() 或者 start() 方法时才会启动协程
    fun main() = runBlocking {
      val time = measureTimeMillis {
        val one = async(start = CoroutineStart.LAZY) { doSomething1() }
        val two = async(start = CoroutineStart.LAZY) { doSomething2() }
        one.start()
        two.start()
        println(" 函数1返回结果 ${one.await()} 函数2返回结果 ${two.await()} ")
      }
      println(" 总耗时:$time ")
    }
    // 挂起函数1
    suspend fun doSomething1(): Int {
      println(" 挂起函数1执行开始 ")
      delay(1000L)
      println(" 挂起函数1执行结束 ")
      return 11
    }
    // 挂起函数2
    suspend fun doSomething2(): Int {
      println(" 挂起函数2执行开始 ")
      delay(1000L)
      println(" 挂起函数2执行结束 ")
      return 22
    }
    执行结果:
    挂起函数1执行开始  
    挂起函数2执行开始  
    挂起函数1执行结束  
    挂起函数2执行结束  
    函数1返回结果 11 函数2返回结果 22  
    总耗时:1035
    

    异步风格的函数

    /**
     * 异步风格的async函数
     * 通过GlobalScope.async{}引用的异步协程生成器来调用
     * 并不是挂起函数 所以说可以在任何地方调用
     */
    fun main() {
      val time = measureTimeMillis {
        // 调用下面函数意味着用异步的形式来执行操作
        val oneAsync = someThingOneAsync()
        val twoAsync = someThingTwoAsync()
        // 因为await()是挂起函数 所以需要在协程和其它挂在函数中执行
        runBlocking {
          println(" 函数1结果:${oneAsync.await()} 函数2结果:${twoAsync.await()} ")
        }
      }
      println(" 总耗时:$time ")
    }
    fun someThingOneAsync() = GlobalScope.async { doOne() }
    fun someThingTwoAsync() = GlobalScope.async { doTwo() }
    // 挂起函数1
    suspend fun doOne(): String {
      println("挂起函数1开始执行")
      delay(1000L)
      println("挂起函数1执行完毕")
      return "小黄一号"
    }
    // 挂起函数2
    suspend fun doTwo(): String {
      println("挂起函数2开始执行")
      delay(1000L)
      println("挂起函数2执行完毕")
      return "小黄二号"
    }
    

    问题点:如果在 val oneAsync = someThingOneAsync() 和 oneAsync.await() 之间的代码逻辑出现错误 出现异常 导致现有的任务会被停掉 此时全局的错误处理者会捕获异常并不会让程序停止 那就意味着 someThingOneAsync()函数仍然还在后台继续运行(因为其协程作用域是GlobalScope) 之后的代码逻辑还会继续执行

    1. 要想解决上述问题 可以使用async结构化并发

    async结构化并发

    • 如果 concurrentSum() 函数发生错误并引发异常,则在其作用域中启动的所有协程都将被取消
    /**
     * async结构化并发
     */
    fun main() = runBlocking<Unit> {
      val time = measureTimeMillis {
        println("成绩总和:${coroutineSum()} ")
      }
      println("总耗时 $time ")
    }
    suspend fun coroutineSum(): Int = coroutineScope {
      val async1 = async {
        doSomeOne()
      }
      val async2 = async {
        doSomeTwo()
      }
      async1.await() + async2.await()
    }
    // 挂起函数1
    suspend fun doSomeOne(): Int {
      println("挂起函数1开始执行")
      delay(1000L)
      println("挂起函数1结束执行")
      return 10
    }
    // 挂起函数2
    suspend fun doSomeTwo(): Int {
      println("挂起函数2开始执行")
      delay(1000L)
      println("挂起函数2结束执行")
      return 11
    }
    执行结果:
    挂起函数1开始执行
    挂起函数2开始执行
    挂起函数1结束执行
    挂起函数2结束执行
    成绩总和:21  
    总耗时 1035
    取消例子:
    // 机构化并发 异常取消机制例子
    fun main() = runBlocking<Unit> {
      try {
        coroutineTest()
      } catch (e: Exception) {
        println("异常捕获${e.message}")
      }
    }
    suspend fun coroutineTest(): Int = coroutineScope {
      val one = async<Int> {
        try {
          delay(Long.MAX_VALUE)
          22
        } finally {
          println("finally执行")
        }
      }
      val two = async<Int> {
        println("异常操作执行")
        throw ArithmeticException()
      }
      one.await() + two.await()
    }
    执行结果:
    异常操作执行
    finally执行
    异常捕获null
    

    谢谢亲们的关注支持 记得点赞哦!

    相关文章

      网友评论

        本文标题:组合挂起函数

        本文链接:https://www.haomeiwen.com/subject/jkjobktx.html