1.默认顺序
我们有两个耗时操作doSomthingOne和doSomthingTwo,例如网络请求数据,但是在协程中的代码执行顺序是按顺序的,等待doSomthingOne执行完在执行doSomthingTwo。
package com.example.kotlin01
import kotlinx.coroutines.*
suspend fun main() {
runBlocking {
var job = launch {
var result1 = doSomthingOne()
println(result1)
var result2 = doSomthingTwo()
println(result2)
println(result1+result2)
}
}
}
suspend fun doSomthingOne(): Int {
delay(2000)
return 13
}
suspend fun doSomthingTwo(): Int {
delay(1000)
return 15
}
13
15
28
2.使用 async 并发
第一个例子中,执行两个耗时操作是按照顺序同步执行的,但是很多时候,我们在做请求网络耗时操作的时候希望是异步,并发执行的。我们通过async 类似launch单独启动协程,返回的是Deferred非阻塞对象,可以调用await()取出返回值。Deferred 也实现了job接口,可以取消协程。以下我们通过同步的代码完成异步并发的业务
package com.example.kotlin01
import kotlinx.coroutines.*
suspend fun main() {
runBlocking {
var result1 = async {
doSomthingOne()
}
println("${result1.await()}")
var result2 = async {
doSomthingTwo()
}
println("${result2.await()}")
println("${result1.await()}+${result2.await()}")
}
}
suspend fun doSomthingOne(): Int {
delay(2000)
return 13
}
suspend fun doSomthingTwo(): Int {
delay(1000)
return 15
}
13
15
13+15
以上开启了两个协程,分别打印了第一个结果和第二个结果。
3.惰性启动
可以设置async的start = CoroutineStart.LAZY,这样只有手动调用deffer的start方法或者await方法,协程才会执行
package com.example.kotlin01
import kotlinx.coroutines.*
suspend fun main() {
runBlocking {
var result1 = async(start = CoroutineStart.LAZY) {
doSomthingOne()
}
var result2 = async(start = CoroutineStart.LAZY) {
doSomthingTwo()
}
//
}
}
suspend fun doSomthingOne(): Int {
delay(2000)
println("doSomthingOne")
return 13
}
suspend fun doSomthingTwo(): Int {
delay(1000)
println("doSomthingTwo")
return 15
}
设置 CoroutineStart.LAZY之后,没有手动调用start和await方法,doSomthingOne和doSomthingTwo两个函数没有执行
package com.example.kotlin01
import kotlinx.coroutines.*
suspend fun main() {
runBlocking {
var result1 = async(start = CoroutineStart.LAZY) {
doSomthingOne()
}
var result2 = async(start = CoroutineStart.LAZY) {
doSomthingTwo()
}
result1.start()
result2.start()
println("${result1.await()}+${result2.await()}")
}
}
suspend fun doSomthingOne(): Int {
delay(2000)
println("doSomthingOne")
return 13
}
suspend fun doSomthingTwo(): Int {
delay(1000)
println("doSomthingTwo")
return 15
}
doSomthingTwo
doSomthingOne
13+15
手动调用之后,两个协程执行了。
4.异步风格的函数
package com.example.kotlin01
import kotlinx.coroutines.*
suspend fun main() {
runBlocking {
var result1 = doSomthingOneAsync()
var result2 = doSomthingTwoAsync()
println("${result1.await()} and ${result2.await()}")
}
}
fun doSomthingOneAsync() = GlobalScope.async {
doSomthingOne()
}
fun doSomthingTwoAsync() = GlobalScope.async {
doSomthingTwo()
}
suspend fun doSomthingOne(): Int {
delay(2000)
println("doSomthingOne")
return 13
}
suspend fun doSomthingTwo(): Int {
delay(1000)
println("doSomthingTwo")
return 15
}
doSomthingTwo
doSomthingOne
13 and 15
以上的方式的缺点在于,如果 var result2 = doSomthingTwoAsync()这行出现错误,程序抛出异常,doSomthingOneAsync会继续执行,因为其协程作用域是 GlobalScope。
5.使用 async 的结构化并发
为了防止第4点的问题,我们通过使用 async 的结构化并发解决
package com.example.kotlin01
import kotlinx.coroutines.*
suspend fun main() {
println("${doSum()}")
}
suspend fun doSum(): Int = coroutineScope {
var result1 = async { doSomthingOne() }
var result2 = async { doSomthingTwo() }
result1.await() + result2.await()
}
suspend fun doSomthingOne(): Int {
delay(2000)
println("doSomthingOne")
return 13
}
suspend fun doSomthingTwo(): Int {
delay(1000)
println("doSomthingTwo")
return 15
}
doSomthingTwo
doSomthingOne
28
如果doSum函数出现异常,那么期作用域内的协程都会被取消。从main函数来看,两个协程也是并发执行的。
网友评论