跳转到内容

是协程不是携程

至少在做某些耗时操作的时候(比如网络请求和文件读写)要用到它

一般来说协程比线程好使,协程里可以用delay挂起,和线程的sleep挺不同

kt里边能开协程的方式挺多

比如

GlobalScope.launch {
println("codes run in coroutine scope")
delay(1500)
println("Ciallo~(∠·ω< )⌒★")
}

delay只会挂起这个协程,不像sleep会祸及自身与包含的协程

再如

runBlocking {
launch {
println("launch1")
delay(1000)
println("launch1 finished")
}
launch {
println("launch2")
delay(1000)
println("launch2 finished")
}
}

runBlocking如果不跑完,那父线程也不会结束

在协程里边可以用很多个launch来开很多个协程

当然如果不是像runBlocking这种东西外边的线程(协程)结束了那里边的协程也会结束

在函数前面加个suspend就是挂起(暂停)函数,挂起函数里面也可以用delay来咋瓦鲁多

比如

suspend fun printDot() {
println(".")
delay(1000)
println(".")
}

但是如果不在协程里面是不能delay的,所以可以让它继承自coroutineScope这个会创建一个协程的函数,变成这样(coroutineScoperunBlocking一样自己不结束上一级也不结束)

suspend fun printDot() = coroutineScope {
println(".")
delay(1000)
println(".")
}

然后这玩意放哪都能生效了

对于大多数启动协程的方法而言,这个参数不是必须的,只有withContext()强制需要

添加这个参数就能添加这个参数(废话

CoroutineScope(Dispatchers.IO)让协程在IO线程池中进行

CoroutineScope(Dispatchers.Main)可以在主线程执行UI相关操作(这是Android独享)

CoroutineScope(Dispatchers.Default)则是一种默认的低并发的策略

GlobalScope会创建一个与应用同寿的协程,实际中这样用会出现警告波浪线

lifecycleScope会创建一个与现有Activity或Fragment同寿的协程

viewModelScope则是创建和ViewModel同寿的协程

CoroutineScope可以创建自定义的作用域

事实上上面的launch会返回一个Job对象,用来管理这个协程的一些关系,也可以拿来取消这个协程,比如

val job = GlobalScope.launch {
// 我不是代码
}
job.cancel()

然后就会有人发现:每个协程都要一个Job的话,那协程一多起来不得麻烦死

于是为了解决这种神奇的麻烦问题,可以像下面这样用Job

val job = Job()
val scope1 = CoroutineScope(job) // 在job的作用域里
val scope2 = CoroutineScope(job) // 也在job的作用域里
scope1.launch {
// 我也不是代码
}
scope2.launch {
// 我说我是代码你信吗
}
job.cancel() // 全部取消

这样可就方便多了,而且如果你想的话,还可以这样写

val myScope = CoroutineScope(Job() + Dispatchers.Default)

launch一样,async也可以拿来启动一个协程,但只能在协程里面启动

async最大的特色就是可以搭配await()来获得其启动的协程的返回值,由于要获得返回值,所以await一定要等对应的协程跑完才会让你继续跑

下面就是书上的某个例子

runBlocking {
val start = System.currentTimeMillis()
val result1 = async {
delay(1000)
5 + 5
}.await()
val result2 = async {
delay(1000)
4 + 6
}.await()
println("result is ${result1 + result2}.")
val end = System.currentTimeMillis()
println("cost ${end - start} ms.")
}

最终的运行结果是超过2000ms的,因为每个await()都会等一秒钟

改成这样就一共只要一秒钟了:

runBlocking {
val start = System.currentTimeMillis()
val result1 = async {
delay(1000)
5 + 5
}
val result2 = async {
delay(1000)
4 + 6
}
println("result is ${deferred1.await() + deferred2.await()}.")
val end = System.currentTimeMillis()
println("cost ${end - start} ms.")
}

显然都在print那里await()了,真是省时省事

这玩意在效果上就是async的简化版

runBlocking {
val result = withContext(Dispatchers.Default) {
5 + 5
}
println(result)
}

相当于

runBlocking {
val result = async{
5 + 5
}.await()
println(result)
}

如此而已