什么是协程
我个人的理解,协程是一种可以让程序“挂起”的技术实现。“挂起”是指将当前程序运行的上下文信息全部保存起来,并可以在后续期间恢复整个现场的一种能力。
例如,Thread.sleep()
而协程不依赖操作系统或者虚拟机,在线程的基础上,通过一系列的原语(关键字)和利用编译器进行转换来实现“挂起”。
协程有什么用
协程最大的用处是可以把回调风格的逻辑(一般是处理并发),写成堵塞风格,而不会发生真正的线程堵塞(前提是要写得对)。
几个关键的概念
要理解协程,必须要在头脑里形成一个与具体实现无关的协程的模型。先记住几个关键的概念:Scope、CoroutineContext、suspend、resume,它们的作用分别是:
- scope: 管理自身范围内的协程。
- CoroutineContext:协程运行的上下文环境,保存着协程运行的所有状态。可嵌套。
- suspend:让程序挂起的操作。
- resume:让程序恢复的操作。
通常情况下,一次使用协程的代码如下所示:
scope.createNewCoroutine(context) { context ->
...
result = doSomthingAsync() {
...
context.resume
}
context.suspend
...
result.get()
...
}
实际上无需显式地进行resume和suspend操作,整体看起来是堵塞式的。
如何使用协程
理解了上面的模型后,下面介绍一下如何使用kotlin的协程。注意,这里不展开解释kotlin的协程实现。
我们通过三个例子来初步认识协程:
eg1:
启动协程前,我们需要一个scope,kotlin预置了众多scope。上面的例子中以GlobalScope为例,GlobalScope.launch()创建了一个协程的运行环境,在其范围内,suspend-resume的机制是有效的。代码里log(2)运行在协程的环境中,但是没有suspend操作。GlobalScope.launch()返回了一个Job对象,此对象类似于java的Thread,用于控制所对应的协程运行环境的生命周期。
eg2:
上面的例子中,GlobalScope.launch()传入了Dispatcher.IO。Dispatcher.IO称之为调度器,实际上是一种CoroutineContext。Dispatcher.IO指定了其内部协程代码运行所在的线程为IO线程。注意,CoroutineContext由于重写了plus运算符,所以可以叠加(嵌套)。
eg3:
fun main(args: Array<String>) = runBlocking() {
launch() {
println("Coroutine start " + Thread.currentThread().hashCode())
launch() {
println("Child coroutine start " + Thread.currentThread().hashCode())
delay(1000)
println("Child coroutine end " + Thread.currentThread().hashCode())
}
println("Coroutine end " + Thread.currentThread().hashCode())
}
println("Done " + Thread.currentThread().hashCode())
}
打印出:
Done 1851691492
Coroutine start 1851691492
Coroutine end 1851691492
Child coroutine start 1851691492
Child coroutine end 1851691492
上述例子中,中间通过launch关键字创建了一个新的子协程。delay(1000)调用时,内部进行了suspend操作(delay是一个suspend函数),所以"Coroutine end"会比"Child coroutine end"更早打印出来。值得注意,所有print语句都是在同一线程上进行的。这里可以明显看出与线程的区别:delay函数并没有堵塞线程,协程在delay处“挂起”了,1000毫秒后恢复。注意这里线程并没有“挂起”,“挂起”的是协程,就如进程和线程的关系,线程堵塞时进程一样在执行。这里协程“挂起”了,但是线程还在继续驱动着众多协程继续执行。
为什么要用协程?
通常情况下,堵塞式的写法在理解难度上总是比回调式的写法要低,但是在面向真实用户时,为了保证交互的流畅度(即不能堵塞UI线程),会采用回调式的写法去处理一系列的复杂逻辑。协程的出现,让我们有了在不堵塞UI线程的基础上,用堵塞式的写法实现业务逻辑。
协程与线程的关系,就像线程与进程的关系一样。使用线程,我们可以不堵塞进程。使用协程,我们可以不堵塞线程。
nb!
nb2
nb3
0yyvlj
915u4m
Your point of view caught my eye and was very interesting. Thanks. I have a question for you.
Thank you for your sharing. I am worried that I lack creative ideas. It is your article that makes me full of hope. Thank you. But, I have a question, can you help me?
Good shout.
thcv gummies area 52
live resin carts area 52
buy thca area 52
best cbd sleep edibles area 52
liquid diamonds area 52
full spectrum cbd gummies area 52
best thca flower area 52
indica gummies area 52
live rosin gummies area 52
liquid thc area 52
live resin gummies area 52
snow caps area 52
thca diamonds area 52
best amanita edibles area 52
thc sleep gummies area 52
best sativa thc carts area 52
mood thc gummies area 52
thc oil area 52
IQ