Kotlin

组合挂起函数

2020-11-15  本文已影响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并发

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

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结构化并发

/**
 * 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

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

上一篇下一篇

猜你喜欢

热点阅读