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();

在这里插入图片描述
现在,假设我们要调用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")
}

程序输出是这样的:

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

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

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

只有依靠上述突出显示的更改才能将命令式代码风格转换为异步代码风格。

在这里插入图片描述

协程允许我们以流畅的方式创建异步程序,而且协程是基于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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值