本文基于协程官方文档讲解,具体可查看here。
一、顺序执行的挂起函数
定义两个挂起函数,在同一个协程体里面执行
suspend fun doSomeOne(): Int {
delay(1000)
return 12;
}
suspend fun doSometwo(): Int {
delay(2000)
return 22;
}
fun main() {
runBlocking(Dispatchers.IO) {
val time = measureTimeMillis {
doSomeOne()
doSometwo()
}
printMsg("耗时$time")
}
}
kt的语法糖
measureTimeMillis测试耗时很方便。
1.1、使用async await来并发处理下
fun main()= runBlocking {
val time= measureTimeMillis {
val one= async { doSomeOne() }
val two=async { doSometwo() }
printMsg("${one.await()} ${two.await()}")
}
printMsg("耗时$time")
}
如果你不小心写成下面👇这样,就不一样结果了.串行执行了。
fun main() = runBlocking {
val time = measureTimeMillis {
val one = async { doSomeOne() }.await()
val two = async { doSometwo() }.await()
}
printMsg("耗时$time")
}
1.2、async支持懒加载的启动模式
fun main() = runBlocking {
val time = measureTimeMillis {
val one = async(start=CoroutineStart.LAZY) { doSomeOne() }
val two = async(start=CoroutineStart.LAZY) { doSometwo() }
printMsg("${one.await()} ${two.await()} ")
}
printMsg("耗时$time")
}
这里的懒加载就成了串行执行。
当懒加载遇上start()方法,就又可以并发执行了。
fun main()= runBlocking {
val time= measureTimeMillis {
val one= async(start=CoroutineStart.LAZY) { doSomeOne() }
val two=async(start=CoroutineStart.LAZY) { doSometwo() }
one.start()
two.start()
printMsg("${one.await()} ${two.await()} ")
}
printMsg("耗时$time")
}
1.3、GlobalScope.async不是挂起函数,但可调用挂起函数
fun someUsefulOneAsync()= GlobalScope.async { //不是挂起函数
doSomeOne()
}
fun someUsefulTwoAsync()= GlobalScope.async { //不是挂起函数
doSometwo()
}
suspend fun doSomeOne():Int{
delay(1000)
return 12;
}
suspend fun doSometwo():Int{
delay(2000)
return 22;
}
fun main() = runBlocking {
val job = launch(Dispatchers.Default) {
val time = measureTimeMillis {
val one = someUsefulOneAsync()
val two = someUsefulTwoAsync()
printMsg("${one.await()}")
printMsg("${two.await()}")
}
printMsg("$time")
}
printMsg("Done")
delay(1200)
job.cancel()
}
这里
GlobalScope.async调用挂起函数,而且它可以正常地响应取消。
1.4 async结构化的并发
suspend fun concurrentSum():Int = coroutineScope {
val one = async { doSomeOne() }
val two = async { doSometwo() }
one.await()+two.await()
}
suspend fun doSomeOne():Int{
delay(1000)
return 12;
}
suspend fun doSometwo():Int{
delay(2000)
return 22;
}
fun main()= runBlocking {
launch(Dispatchers.Default) {
val time = measureTimeMillis {
printMsg("${concurrentSum()}")
}
printMsg("${time}")
}
printMsg("Done")
}
coroutineScope在这里就是保证让其block执行完才能走后面的。
1.4.1 async结构化的并发捕捉异常
suspend fun concurrentSum():Int= coroutineScope {
val one = async {
try{
delay(10000L)
43
}finally {
printMsg("first child was cancelled")
}
}
val two= async<Int> {
printMsg("second child throw an exception")
throw ArithmeticException()
}
one.await()+two.await()
}
try finally就是前面讲过的,协程抛异常没有捕捉,就奔溃了,防止奔溃,可以在协程体上try catch。
fun main() = runBlocking {
try { //#1
launch(Dispatchers.Default) {
try { //#2
val time = measureTimeMillis {
printMsg("${concurrentSum()}")
}
printMsg("${time}")
} catch (e: Exception) {
printMsg("#2 $e")
}
}
printMsg("Done")
} catch (e: Exception) {
printMsg("#1 $e")
}
}
try catch 这里有两处,#1 和 #2 ,这里
能catch这个异常只能是#2,注意,仅try catch最外层#1是捕捉不了这个异常的,app会奔溃。