Kotlin: Coroutines协程学习笔记(一)

tech2022-07-16  156

一、什么是协程

协程是一种协作式的计算机程序并发调度的实现,程序可以主动挂起或者恢复执行,本质上,协程是轻量级的线程。

二、协程和线程的关系和区别

1、协程是协作式的,线程是抢占式的。协程是由程序来控制什么时候进行切换的,而线程是有操作系统来决定线程之间的切换的。

2、一个线程可以包含多个协程。但是有一点必须明确的是,一个线程的多个协程的运行是串行的。

3、和多线程比,协程没有线程切换的开销,执行效率更高,性能更具优势。因而协程适合io密集型的程序,多线程适合计算密集型的程序(适用于多核cpu的情况)。当你的程序大部分是文件读写操作或者网络请求操作的时候,这时你应该首选协程。因为这些操作大部分不是利用cpu进行计算而是等待数据的读写。

4、协程,能简化异步执行的代码,书写更优雅,避免回调地狱。

三、基本概念

1、suspend :挂起函数

suspend fun requestToken(): Token { ... }   // 挂起函数 suspend fun createPost(token: Token, item: Item): Post { ... }   fun processPost(post: Post) { GlobalScope.launch { // 创建一个新协程       val token = requestToken()       val post = createPost(token, item)       processPost(post)       // 需要异常处理,直接加上 try/catch 语句即可   } }

requestToken和createPost函数前面有suspend修饰符标记,这表示两个函数都是挂起函数。挂起函数能够以与普通函数相同的方式获取参数和返回值,但是调用函数可能挂起协程(如果相关调用的结果已经可用,库可以决定继续进行而不挂起),挂起函数挂起协程时,不会阻塞协程所在的线程。挂起函数执行完成后会恢复协程,后面的代码才会继续执行。需要注意的是,挂起函数只能在协程中或其他挂起函数中调用。

2、GlobalScope.launch:协程的创建

由上可知,我们可以通过GlobalScope.launch创建一个协程

(创建协程有三种方式: launch、async、runBlocking)

GlobalScope.launch的源码如下:

public fun CoroutineScope.launch(   context: CoroutineContext = EmptyCoroutineContext,   start: CoroutineStart = CoroutineStart.DEFAULT,   block: suspend CoroutineScope.() -> Unit )

3、CoroutineContext:协程上下文

CoroutineContext,协程上下文,是一些元素的集合,主要包括 Job 和 CoroutineDispatcher 元素,可以代表一个协程的场景。

(1) CoroutineDispatcher,协程调度器,决定协程所在的线程或线程池。主要有以下几种调度器:

Dispatchers.Main:主线程,用来处理UI交互和一些轻量级任务Dispatchers.IO:非主线程,专为磁盘和网络IO进行了优化。适用于数据库、文件读写,网络处理等场景Dispatchers.Default:默认调度器,非主线程,专为CPU密集型任务进行了优化,适用于数组排序,JSON解析等场景Dispatchers.Unconfined:不限定调度器,适用于执行不消耗 CPU 时间的任务,以及不更新如UI的协程

(2) Job & Deferred

Job 可以取消,且有简单生命周期。有几种生命周期状态:new,active,Completing,Cancelling, Cancelled,Completed ​​​​​​。

Job 完成时是没有返回值的,而Deferred是有返回值的,Deferred是Job的子类。

4、runBlocking

创建一个新的协程同时阻塞当前线程,直到协程结束。

5、withContext

withContext{}不会创建新的协程,在指定协程上运行挂起代码块,并挂起该协程直至代码块运行完成。

6、async

后台创建一个新协程,相比于launch,它有返回值,返回的是 Deferred 类型

获取返回值的方法是通过await()函数,这也是个挂起函数,调用时会挂起当前协程直到 async 中代码执行完并返回某个值。

 

最新回复(0)