Kotlin学习笔记25 协程part5 协程的同步与异步

参考链接

示例来自bilibili Kotlin语言深入解析 张龙老师的视频

1 程序运行时间统计measureTimeMillis

/**
 * 程序运行时间统计measureTimeMillis
 *
 * Kotlin 提供了一个便利的内置函数来统计运行时间(measureTimeMillis)
 */

fun main() = runBlocking {
    // Executes the given block and returns elapsed time in milliseconds.
    val elapsedTime = measureTimeMillis {
        println("start calculate...")
        val value1 = intValue1() // 串行调用挂起方法 时间为挂起函数执行时间累加值
        val value2 = intValue2()
        println("$value1 + $value2 = ${value1 + value2}")
    }

    println("total time: $elapsedTime")
}

private suspend fun intValue1(): Int {
    delay(2000)
    return 15
}

private suspend fun intValue2(): Int {
    delay(3000)
    return 20
}

class HelloKotlin1 {
}

2 使用async与await实现并发

/**
 * 使用async与await实现并发
 * 从概念上讲,async就像是launch一样。它会开启一个单独的协程,这个协程也是轻量级线程,可以与其他协程并发工作。区别在于,launch
 * 会返回一个Job 但是Job不会持有任何结果值,而async会返回一个Deferred,Deferred是一个轻量级非阻塞的future,代表一个promise
 * 可以在之后提供一个结果值
 *
 * 可以通过在一个deferred上调用await方法来获取最终计算的结果值,Deferred是Job的子类,因此可以在需要时取消Job
 */
fun main() = runBlocking {
    val elapsedTime = measureTimeMillis {
        println("start calculate...")
        val deferred1 = async { intValue1() } // 并行调用挂起方法
        val deferred2 = async { intValue2() } // 并行调用挂起方法
        val value1 = deferred1.await() // 调用await方法来获取最终计算的结果值
        val value2 = deferred2.await()
        println("$value1 + $value2 = ${value1 + value2}")
    }

    println("total time: $elapsedTime")
}

private suspend fun intValue1(): Int {
    delay(2000)
    return 15
}

private suspend fun intValue2(): Int {
    delay(3000)
    return 20
}
class HelloKotlin2 {
}

3 使用async延时启动协程

注意这里不小心会搞成串行执行协程

/**
 * 使用async延时启动协程
 *
 * 我们可以通过将async方法的start方法参数设置为 CoroutineStart.LAZY来实现协程的延迟执行
 * 在这种情况下,协程会在如下情况执行:
 * 1.调用deferred的await方法
 * 2.调用job的start方法
 */
fun main() = runBlocking {
    val elapsedTime = measureTimeMillis {

        val deferred1 = async(start = CoroutineStart.LAZY) { intValue1() } // 并行调用挂起方法
        val deferred2 = async(start = CoroutineStart.LAZY)  { intValue2() } // 并行调用挂起方法
        println("hello...")
        Thread.sleep(2000)
        // 如果注释调下面两个start调用 协程又会变成串行执行
        deferred1.start()
        deferred2.start()
        println("1...")
        val value1 = deferred1.await() // 调用await方法来获取最终计算的结果值 这里需要等待2s(从deferred1.start调用开始计时)
        println("2...")
        val value2 = deferred2.await() // 调用await方法来获取最终计算的结果值 这里需要等待3s(从deferred2.start调用开始计时)
        println("3...")
        println("$value1 + $value2 = ${value1 + value2}")
    }

    println("total time: $elapsedTime")
}

private suspend fun intValue1(): Int {
    delay(2000)
    return 15
}

private suspend fun intValue2(): Int {
    delay(3000)
    return 20
}

class HelloKotlin3 {
}

4 异步风格的代码

/**
 * 异步风格的代码
 *
 * 不推荐??原因不理解 TODO
 */
fun main() {
    val elapsedTime = measureTimeMillis {
        val deferred1 = intValue1Async() // 调用“普通”方法
        val deferred2 = intValue2Async() // 调用“普通”方法
        runBlocking {
            println("the answer is :${deferred1.await()} + ${deferred2.await()} = ${deferred1.await() + deferred2.await()}")
        }
    }
    println("total time: $elapsedTime")
}

private suspend fun intValue1(): Int {
    delay(2000)
    return 15
}

private suspend fun intValue2(): Int {
    delay(3000)
    return 20
}

// GlobalScope.async返回一个Deferred
// 普通方法内部调用异步挂起方法 实际使用该方法看起来就像操作普通方法操作异步方法一样
fun intValue1Async() = GlobalScope.async {
    intValue1()
}

// 看起来是普通方法 实际是异步方法
// 1 因为这个方法是普通方法 所以方法调用时可以当做普通方法调用
// 2 如果要获取值 需要使用协程的异步方式执行来获取值
fun intValue2Async() = GlobalScope.async {
    intValue2()
}

class HelloKotlin4 {
}

5 正确的异步风格的代码

/**
 * 正确的异步风格的代码
 *
 * 推荐使用一个挂起函数调用需要并行执行的另外的挂起方法
 * 但是还是不明白HelloKotlin4中的代码有什么缺陷
 * 使用async进行结构化并发程序开发
 */
fun main() = runBlocking {
    val elapsedTime = measureTimeMillis {
        println("the answer is ${intSum()}")
    }
    println("total time: $elapsedTime")
}

private suspend fun intValue1(): Int {
    delay(2000)
    return 15
}

private suspend fun intValue2(): Int {
    delay(3000)
    return 20
}

private suspend fun intSum(): Int = coroutineScope {// coroutineScope会创建一个新的协程作用域
    val deferred1 = async { intValue1() }
    val deferred2 = async { intValue2() }
    deferred1.await() + deferred2.await()
}

class HelloKotlin5 {
}

6 协程嵌套异常取消问题

/**
 * 协程嵌套异常取消问题
 * 当一个协程内部嵌套两个协程时
 * 子协程其中一个出现异常 会导致另外一个子协程以及父协程都被取消
 */

fun main() = runBlocking {
    try {
        failureComputation()
    }finally {
        println("main end")
    }
}

private suspend fun failureComputation(): Int = coroutineScope {
    val value1 = async {
        try {
            delay(90000)
            50
        } finally {
            println("value1 end")
        }
    }
    val value2 = async {
        Thread.sleep(2000)
        println("value2 throws exception")
        throw IllegalArgumentException()
    }

    value1.await() + value2.await()
}

class HelloKotlin6 {
}

你可能感兴趣的:(Kotlin,kotlin,java)