前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kotlin 并发编程之"协程"

Kotlin 并发编程之"协程"

作者头像
一个会写诗的程序员
发布2019-07-14 07:10:48
8880
发布2019-07-14 07:10:48
举报

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 协程,需要单独添加依赖:

代码语言:javascript
复制
compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.2.2'

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

代码语言:javascript
复制
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:

代码语言:javascript
复制
* 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.

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

代码语言:javascript
复制
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函数如下:

代码语言:javascript
复制
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
}

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

代码语言:javascript
复制
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

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

代码语言:javascript
复制
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 开发者社区

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.07.11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Kotlin 并发编程之"协程"
  • Composing suspending functions
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档