• Kotlin 协程异步编程


    本文将展示如何轻松高效地使用Kotlin协程写出异步代码。

    首先,在Java中,异步编程有哪些问题?

    1. 写异步代码很复杂
    2. 把命令式风格的代码转为异步代码很麻烦,反之亦然

    这是Java异步代码示例:

    CompletableFuture.supplyAsync(() -> 0)
           .thenApply(i -> { logger.info("First step: {}", i); return i; }) 
           .thenApply(i -> { logger.info("Second step: {}", i); return i; }) 
           .whenComplete((value, t) -> {
               if (t == null) {
                   logger.info("success: {}", value);
               } else {
                   logger.warn("failure: {}", t.getMessage()); 
               }
           })
           .thenApply(i -> { logger.info("Third step: {}", i); return i; }) 
           .handle((value, t) -> {
               if (t == null) {
                   return value + 1;
               } else {
                   return -1; 
               }
           })
           .thenApply(i -> { logger.info("Fourth step: {}", i); return i; }) 
           .join();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述
    现在,假设我们要调用3个web服务,每个web服务响应时间为1秒。用Kotlin 写出来的程序是这样的:

    fun repository1(input : Int) : String {
        Thread.sleep(1000)
        return "Response of web service $input"
    }
    
    fun repository2(input : Int) : String {
        Thread.sleep(1000)
        return "Response of web service $input"
    }
    
    fun repository3(input : Int) : String {
        Thread.sleep(1000)
        return "Response of web service $input"
    }
    
    fun main() {
    
        val startTime = System.currentTimeMillis()
    
        val result1 = repository1(1)
        val result2 = repository2(2)
        val result3 = repository3(3)
    
    
        val apisResponses = """
            ${result1}
            ${result2}
            ${result3}
            """.trimIndent()
    
        println(apisResponses)
        println("Time taken to get the response: ${(System.currentTimeMillis() - startTime)/1000} sec")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    程序输出是这样的:

    Response of web service 1
    Response of web service 2
    Response of web service 3
    Time taken to get the response: 3 sec
    
    • 1
    • 2
    • 3
    • 4

    可以看到,使用协程写的异步代码,性能得到了大幅度提升。

    你是否注意到需要对代码语法进行多少更改才能将命令式代码转换为异步风格?
    在这里插入图片描述

    Only the above highlighted changes were required to convert the imperative style of code to the asynchronous style of code.只有依靠上述突出显示的更改才能将命令式代码风格转换为异步代码风格。

    在这里插入图片描述

    协程允许我们以流畅的方式创建异步程序,而且协程是基于CPS(Continuation-passing style 续体传递风格)编程的概念。

    什么是CPS编程?

    在函数式编程中,续体传递风格(continuation passing style,CPS)是一种编程风格,其中控制以续体的形式显式传递。

    以CPS风格编写的函数需要一个额外的参数:续体。例如,只有一个参数的函数,当CPS函数计算出结果,它会调用以该值为参数的续体函数来返回结果。这意味着,当调用CPS函数时,调用函数需要提供一个子程序,子程序的“return”值将会被调用。以这种形式表达代码可以使许多事情更直观,而这些在直接风格中是隐式不直观的。其中就包括:过程返回,在调用续体时变得很直观;中间值,都是赋予名称的;参数复制的顺序,这是明确的;还有尾部调用,只需调用传递给调用方的具有相同续体且未被修改的过程。
    在这里插入图片描述

    async{} 和 await()函数是什么?
    async{}是一个协程构建器,它创建一个新的协程,在期望有返回值的情况下使用。

    async 会返回一个 Deferred 对象. 我们在Deferred对象上调用await() 函数 await 函数就会等待,挂起当前的协程,直到async函数运行结束,然后返回协程的值。
    协程作用域 (coroutine scope) 是什么?
    协程作用域是新协程的作用域。每个协程构建器(如launch、async等)都是对协程作用域(CoroutineScope)的扩展,继承其协程上下文(coroutineContext)来自动传播其所有元素和协程的取消。

    获取一个作用域独立实例的最佳方法是调用CoroutineScope()和MainScope()工厂函数,当不再需要这些协同作用域时,要谨慎取消它们。

    挂起函数 (suspend functions)是什么?
    挂起函数是一个可以启动、暂停和恢复的函数。关于挂起函数,需要牢记的最重要的一点是,它们只允许被协程或其他挂起函数调用。

    英文链接:https://medium.com/@akarsh7791/asynchronous-programming-with-kotlin-coroutines-417f7436ee02

  • 相关阅读:
    OpenNebula的配置与应用(一)
    深入理解Java并发锁
    第七章---内置模块
    AlmaLinux 9 x86_64 OVF (sysin)
    深入理解JVM虚拟机第一篇:Java跨平台和字节码以及多语言混合编程
    vue3源码的下载与安装
    Upload-labs(Pass3-4)
    Android Studio Bumblebee | 2021.1.1 发布,快来看看更新了什么
    论文解读(JKnet)《Representation Learning on Graphs with Jumping Knowledge Networks》
    【微服务】mysql + elasticsearch数据双写设计与实现
  • 原文地址:https://blog.csdn.net/mg2flyingff/article/details/125512029