kotlin coroutines 协程
Coroutine 协程,是kotlin 上的一个轻量级的线程库,对比 java 的 Executor,主要有以下特点:
- 更轻量级的 api 实现协程
- async 和 await 不作为标准库的一部分
- suspend 函数,也就是挂起函数是比 java future 和 promise 更安全并且更容易使用
那么实际本质上和线程池有什么区别呢?我的理解是这样的,协程是在用户态对线程进行管理的,不同于线程池,协程进一步管理了不同协程切换的上下文,协程间的通信,协程挂起,对于线程挂起,粒度更小,而且一般不会直接占用到CPU 资源,所以在编程发展的过程中,广义上可以认为 多进程->多线程->协程。
简单使用
首先,要引入 coroutines 的依赖,在你的 build.gradle
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.0'
}
然后下面是一个最简单的例子,在子线程延迟打印一行日志:
fun coroTest() {
// Globals 是 Coroutines 的一个 builder
GlobalScope.launch {
delay(1000L)//Delays coroutine for a given time without blocking a thread and resumes it after a specified time.
Thread.sleep(2000)
Log.i(CO_TAG, "launch ")
}
Log.i(CO_TAG, "----")
}
控制台输出效果如下:
01-05 11:11:40.373 28131-28131/com.yy.yylite.kotlinshare I/coroutine: ----
01-05 11:11:43.375 28131-3159/com.yy.yylite.kotlinshare I/coroutine: launch
也就是说在子线程 delay 1000 毫秒,然后 sleep 2000 毫秒,之后打印出来了,确实达到了我们理想的状态。
接着看下 Android studio 的 cpu profiler,我们可以看到,这里启动了几个新的子线程:
这里会创建名为DefaultDispatch 的子线程,做个一个简单的实验,不断的重复执行上面的代码,并不会无限创建子线程,看了其内部的线程数也是有约束的。这个可能比直接调度线程池,更加节省资源,也避免了极端情况。(实际上 delay() 是一个非阻塞的挂起函数)
blocking 和 non-blocking 函数
delay{} 是 非阻塞函数,Thread.sleep() 则是阻塞函数,coroutines 中使用 runBlocking{} 作为阻塞函数,例如以下代码:
fun testBlockAndNoBlock() {
//非阻塞,子线程
GlobalScope.launch {
delay(1000)
doLog("no-block")
}
doLog("non block test")
//会阻塞主线程
runBlocking {
delay(3000)
doLog("block")
}
doLog("block test")