稀有猿诉

十年磨一剑,历炼出锋芒,说话千百句,不如码二行。

Understanding Coroutines

协程Coroutine是一种轻量级的实现异步的方式,使用上大大简化了以往异步和多线和带来的种种麻烦(如状态同步和锁),今天就来学习一下协程,以及在Kotlin中协程的使用方式。

理解异步

在解释什么是协程之前,得先要理解什么是异步。异步也就是说程序是非阻塞非同步的,并不是按照顺序来执行的。这么说依然很绕,我们来一个简单的例子。比如有这样一个语句:

1
2
3
4
fun main(args: Array<String>) {
     println("world of Coroutine!") // 1
     print("Hello ...") // 2
}

这个代码的输出很明显是

1
2
world of Coroutine
Hello ...

函数的执行是从上到下按我们写的顺序执行的,这就是顺序执行的意思,虽然说编译器会做一些指令重排以期对字节码进行一些优化,但有一个前提就是它不会改变程序的正确性,比如后面语句如果需要前面表达的结果时,一定能保证它们的执行顺序。同步的意思是,执行一个子函数,子函数会占用CPU,直到它运行结束再返回到调用它的函数,继续运行并能把结果带回给调用者,这即是同步的意思。比如这里的println,println没有执行完时,后面的语句是不会执行的。

异步的意思是函数语句的执行并不是按照我们写的顺序来运行的。比如说,前面的函数,如何能输出”Hello …world of Coroutine” ?这就需要让代码实现异步,非顺序的执行。有多种方式,协程就可以实现异步:

1
2
3
4
5
6
7
8
fun main() = runBlocking { // this: CoroutineScope
    launch { // launch a new coroutine and continue
        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
        println("world of Coroutine!") // print after delay
    }
    print("Hello ...") // main coroutine continues while a previous one is delayed
}
// Hello ...world of Coroutine!

协程不是线程

需要特别注意的是协程并不是线程,它并不是实现多线程或者并行的方式,相反,协程是实现异步和并发的方式,它是让多个函数更好的协作以实现异步和并发,并发与并行的区别可以看这里

从它的名字可以看出,它是子例程之间的协作,它是函数的执行,可以挂起,可以继续,但它不会产生阻塞。可以理解为它把线程进行了拆解,分为线程环境的具体函数的执行,协程则是函数的执行。

理解协程的要点是协程只会挂起,不会阻塞,重点转移到了各个函数如何协作,如何设计挂起点。至于并发部分,则交由协程运行的上下文环境(CoroutineContext)来处理。

实战

这时强烈推荐官方的一个实战性的教程,它是一个有具体应用场景且足够的复杂的小项目,大部分代码已实现了,预留了一些任务来练手,并有教程进行讲解,当然也有参考答案,非常适合学习和参考。

参考资料

Comments