美文网首页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

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

相关文章

  • 组合挂起函数

    本节介绍了将挂起函数组合的各种方法。 默认顺序调用 假设我们在不同的地方定义了两个进行某种调用远程服务或者进行计算...

  • 组合挂起函数

    “被suspend关键字所修饰的函数叫做挂起函数,挂起函数(suspending function)可以像普通函数...

  • 组合挂起函数

    挂起函数调用顺序 在协程中顺序调用多个挂起函数 这多个挂起函数执行的顺序和常规代码中一样 默认都是顺序执行的常规代...

  • Kotlin协程组合挂起函数

    一、默认顺序调用 在协程中的,挂起函数像常规的代码⼀样顺序都是默认的。 二、使用 async 并发 async 就...

  • Kotlin学习笔记之 31 协程挂起函数的组合

    首发于公众号: DSGtalk1989 31.协程挂起函数的组合 同步与并发通常情况下,协程中的挂起函数都是同步执...

  • Kotlin进阶-组合挂起函数、协程上下文与调度器

    一.组合挂起函数 1.默认顺序调用 假设我们在不同的地方定义了两个进行某种调用远程服务或者进行计算的挂起函数。我们...

  • Kotlin(十九)协程(组合挂起函数)

    1.默认顺序 我们有两个耗时操作doSomthingOne和doSomthingTwo,例如网络请求数据,但是在协...

  • Jetpack Compose 中的副作用

    启动效果 让我们在可组合对象中运行挂起函数。当LaunchedEffect进入Composition时,它会启动一...

  • 挂起函数

    async 用于处理挂起函数的并发在概念上,async 就类似于 launch。它启动了一个单独的协程,这是一个轻...

  • Kotlin之协程(三)组合挂起函数

    简介 介绍 参考文档 谷歌开发者[https://developer.android.google.cn/kotl...

网友评论

    本文标题:组合挂起函数

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