禅与计算机程序设计艺术SpringBoot极简教程 · Spring Boot Java Web 核心技术

Kotlin 并发编程之"协程"

2019-07-11  本文已影响5人  光剑书架上的书

Kotlin 并发编程之"协程"

Kotlin协程简介

Kotlin, as a language, provides only minimal low-level APIs in its standard library to enable various other libraries to utilize coroutines. Unlike many other languages with similar capabilities, async and await are not keywords in Kotlin and are not even part of its standard library. Moreover, Kotlin's concept of suspending function provides a safer and less error-prone abstraction for asynchronous operations than futures and promises.

kotlinx.coroutines is a rich library for coroutines developed by JetBrains. It contains a number of high-level coroutine-enabled primitives that this guide covers, including launch, async and others.

This is a guide on core features of kotlinx.coroutines with a series of examples, divided up into different topics.

In order to use coroutines as well as follow the examples in this guide, you need to add a dependency on kotlinx-coroutines-core module.

[ https://kotlinlang.org/docs/reference/coroutines/coroutines-guide.html ]

协程是一个轻量级的线程。

Kotlin 中的协程的实现原理是:
coroutine == continuation + coroutine scope.

(关于这个continuation 和 coroutine scope 我们会在后面的文章中介绍.)

想要使用 Kotlin 协程,需要单独添加依赖:

compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.2.2'

先用一个官方的demo,直观认识一下协程:

import kotlinx.coroutines.*

fun main() {
    GlobalScope.launch { // launch a new coroutine in background and continue
        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
        println("World!") // print after delay
    }
    println("Hello,") // main thread continues while coroutine is delayed
    Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}

输出:

Hello,
World!

Kotlin帮我们去完成线程的调度。

而这里GlobalScope.launch就是创建一个协程环境并且启动一个协程。

协程上下文包括了一个 协程调度器,它确定了相应的协程在执行时使用一个或多个线程。协程调度器可以将协程的执行局限在指定的线程中,调度它运行在线程池中或让它不受限的运行。

其中, GlobalScope 继承了 CoroutineScope:

* A global [CoroutineScope] not bound to any job.
*
* Global scope is used to launch top-level coroutines which are operating on the whole application lifetime
* and are not cancelled prematurely.
* Another use of the global scope is operators running in [Dispatchers.Unconfined], which don't have any job associated with them.
*
* Application code usually should use an application-defined [CoroutineScope]. Using
* [async][CoroutineScope.async] or [launch][CoroutineScope.launch]
* on the instance of [GlobalScope] is highly discouraged.

我们再写一个稍微丰富一点的例子:

package com.kotlin.notes.coroutine

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.lang.Thread.sleep

class CoroutineDemo {


    fun doSomething() {
        for (i in 0..5) {
            println(i)
            sleep(1000)
        }

        println("doSomething done")
    }


    suspend fun suspendDoSomething() {
        for (i in 0..5) {
            println(i)
            delay(1000)
        }
    }


}

fun main() = runBlocking {
    val d = CoroutineDemo()
    d.doSomething()

    val job = GlobalScope.launch {
        d.suspendDoSomething()
    }

    println("suspendDoSomething done?")

    job.join()

    println("suspendDoSomething done!")

}

输出:

0
1
2
3
4
5
doSomething done
suspendDoSomething done?
0
1
2
3
4
5
suspendDoSomething done!

Composing suspending functions

下面我们再看一下 suspend 函数的组合调用.

定义两个suspend函数如下:

suspend fun doSomethingA(): Int {
    delay(1000L) // pretend we are doing something useful here
    return 10
}

suspend fun doSomethingB(): Int {
    delay(1000L) // pretend we are doing something useful here, too
    return 10
}

然后,我们调用上面的函数:

val d = CoroutineDemo()

val time = measureTimeMillis {
    val a = d.doSomethingA()
    val b = d.doSomethingB()
    println("The answer is ${a + b}")
}
println("Completed in $time ms")

运行输出:

The answer is 20

Completed in 2026 ms

上面的方式是同步的方式. 下面我们在来看一下异步执行的方式:

val time = measureTimeMillis {
    val a = async { d.doSomethingA() }
    val b = async { d.doSomethingB() }
    println("The answer is ${a.await() + b.await()}")
}
println("Completed in $time ms")

运行输出:

The answer is 20

Completed in 1042 ms

这里的 async 需要运行在一个协程环境之中,所以我们这里用了一个GlobalScope.launch。

async会返回一个Deferred对象,在async方法结束的时候,就会调用await()方法。因此,我们可以通过await()就可以得到异步回调。有了这个特性,我们网络请求的时候就会非常的方便。

[ref:https://kotlinlang.org/docs/reference/coroutines/composing-suspending-functions.html]

本文代码实例源码地址:

https://gitee.com/universsky/kotlin-notes


Kotlin 开发者社区

国内第一Kotlin 开发者社区公众号,主要分享、交流 Kotlin 编程语言、Spring Boot、Android、React.js/Node.js、函数式编程、编程思想等相关主题。

Kotlin 开发者社区
上一篇下一篇

猜你喜欢

热点阅读