Kotlin Coroutines 笔记 (一)

本文介绍了Kotlin中的协程概念,它是如何作为轻量级线程实现无阻塞的异步操作。协程通过CoroutineContext和CoroutineDispatcher进行调度,使用suspend关键字实现挂起功能。文中通过对比协程与线程的创建,展示了协程在资源消耗上的优势。此外,还提到了Job和Deferred等关键概念,以及协程在Android开发中的应用。
摘要由CSDN通过智能技术生成

在这里插入图片描述

一. 协程
Kotlin 在1.1版本之后引入了协程的概念,目前它还是一个试验的API。

在操作系统中,我们知道进程和线程的概念以及区别。而协程相比于线程更加轻量级,协程又称微线程。

协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

Kotlin 的协程是无阻塞的异步编程方式。Kotlin 允许我们使用协程来代替复杂的线程阻塞操作,并且复用原本的线程资源。

Kotlin 的协程是依靠编译器实现的, 并不需要操作系统和硬件的支持。编译器为了让开发者编写代码更简单方便, 提供了一些关键字(例如suspend), 并在内部自动生成了一些支持型的代码。

先举两个例子来说明协程的轻量级,分别创建10w个协程和10w个线程进行测试。

import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.runBlocking

/**

  • Created by tony on 2018/7/18.
    */
    fun main(args: Array) {

    val start = System.currentTimeMillis()

    runBlocking {
    val jobs = List(100000) {
    // 创建新的coroutine
    launch(CommonPool) {
    // 挂起当前上下文而非阻塞1000ms
    delay(1000)
    println(“thread name=”+Thread.currentThread().name)
    }
    }

     jobs.forEach {
         it.join()
     }
    

    }

    val spend = (System.currentTimeMillis()-start)/1000

    println(“Coroutines: spend= $spend s”)

}

10w个协程的创建在本机大约花费 1 秒,经过测试100w个协程的创建大约花费11 秒。
在这里插入图片描述

十万个协程测试.jpeg

import kotlin.concurrent.thread

/**

  • Created by tony on 2018/7/18.
    */
    fun main(args: Array) {

    val start = System.currentTimeMillis()

    val threads = List(100000) {
    // 创建新的线程
    thread {
    Thread.sleep(1000)
    println(Thread.currentThread().name)
    }
    }

    threads.forEach { it.join() }

    val spend = (System.currentTimeMillis()-start)/1000

    println(“Threads: spend= $spend s”)

}
在这里插入图片描述

十万个线程测试.jpeg

10w个线程的创建出现了OutOfMemoryError。

二. 协程常用的基本概念
2.1 CoroutineContext
协程上下文,它包含了一个默认的协程调度器。所有协程都必须在 CoroutineContext 中执行。

2.2 CoroutineDispatcher
协程调度器,它用来调度和处理任务,决定了相关协程应该在哪个或哪些线程中执行。Kotlin 的协程包含了多种协程调度器。

2.3 Continuation
按照字面意思是继续、持续的意思。协程的执行可能是分段执行的:先执行一段,挂起,再执行一段,再挂起…

Continuation 则表示每一段执行的代码,Continuation 是一个接口。

2.4 Job
任务执行的过程被封装成 Job,交给协程调度器处理。Job 是一种具有简单生命周期的可取消任务。Job 拥有三种状态:isActive、isCompleted、isCancelled。

                                                  wait children
+-----+       start      +--------+   complete   +-------------+  finish  +-----------+
| New | ---------------> | Active | -----------> | Completing  | -------> | Completed |
+-----+                  +--------+              +-------------+          +-----------+
   |                         |                         |
   | cancel                  | cancel                  | cancel
   V                         V                         |

±----------+ finish ±-----------+ |
| Cancelled | <--------- | Cancelling | <----------------+
|(completed)| ±-----------+
±----------+

2.5 Deferred
Deferred 是 Job 的子类。Job 完成时是没有返回值的,Deferred 可以为任务完成时提供返回值,并且Deferred 新增了一个状态 isCompletedExceptionally。

                                                wait children

±----+ start ±-------+ complete ±------------+ finish ±----------+
| New | ---------------> | Active | ----------> | Completing | —±> | Resolved |
±----+ ±-------+ ±------------+ | |(completed)|
| | | | ±----------+
| cancel | cancel | cancel |
V V | | ±----------+
±----------+ finish ±-----------+ | ±> | Failed |
| Cancelled | <--------- | Cancelling | <---------------+ |(completed)|
|(completed)| ±-----------+ ±----------+
±----------+

2.6 suspend 关键字
协程计算可以被挂起而无需阻塞线程。我们使用 suspend 关键字来修饰可以被挂起的函数。被标记为 suspend 的函数只能运行在协程或者其他 suspend 函数中。

suspend 可以修饰普通函数、扩展函数和 lambda 表达式。

三. 协程的多种使用方式
Kotlin 的协程支持多种异步模型:

在这里插入图片描述

Kotlin协程支持的异步模型.png

这些异步机制在 Kotlin 的协程中都有实现。

Kotlin 官方对协程提供的三种级别的能力支持, 分别是: 最底层的语言层, 中间层标准库(kotlin-stdlib), 以及最上层应用层(kotlinx.coroutines)。

3.1 协程的hello world版本
使用 launch 和 async 都能启动一个新的协程。

val job = launch {
    delay(1000)
    println("Hello World!")
}

Thread.sleep(2000)

或者

val deferred  = async {

    delay(1000)
    println("Hello World!")
}

Thread.sleep(2000)

它们分别会返回一个 Job 对象和一个 Deferred 对象。

下面使用 runBlocking 来创建协程。

fun main(args: Array) = runBlocking {
launch {
delay(1000)
println(“Hello World!”)
}

delay(2000)

}

runBlocking 创建的协程直接运行在当前线程上,同时阻塞当前线程直到结束。

launch 和 async 在创建时可以使用不同的CoroutineDispatcher,例如:CommonPool。

在 runBlocking 内还可以创建其他协程,例如launch。反之则不行。

总结

Kotlin 的协程能够简化异步编程的代码,使用同步的方式实现异步。协程的概念和理论比较多,第一篇只是一个开始,只整理了其中一些基本概念。

更多的Kotlin学习资料可以扫码免费领取!

《史上最详Android版kotlin协程入门进阶实战》

第一章 Kotlin协程的基础介绍

            ● 协程是什么

            ● 什么是Job 、Deferred 、协程作用域

            ● Kotlin协程的基础用法

img

第二章 kotlin协程的关键知识点初步讲解

            ● 协程调度器

            ● 协程上下文

            ● 协程启动模式

            ● 协程作用域

            ● 挂起函数

img

第三章 kotlin协程的异常处理

            ● 协程异常的产生流程

            ● 协程的异常处理

img

第四章 kotlin协程在Android中的基础应用

            ● Android使用kotlin协程

            ● 在Activity与Framgent中使用协程

            ● ViewModel中使用协程

            ● 其他环境下使用协程

img

第五章 kotlin协程的网络请求封装

            ● 协程的常用环境

            ● 协程在网络请求下的封装及使用

            ● 高阶函数方式

            ● 多状态函数返回值方式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值