Kotlin学习_协程(Coroutines)的使用


Some APIs initiate long-running operations (such as network IO, file IO, CPU- or GPU-intensive work, etc) and require the caller to block until they complete. Coroutines provide a way to avoid blocking a thread and replace it with a cheaper and more controllable operation: suspension of a coroutine.
Coroutines simplify asynchronous programming by putting the complications into libraries. The logic of the program can be expressed sequentially in a coroutine, and the underlying library will figure out the asynchrony for us. The library can wrap relevant parts of the user code into callbacks, subscribe to relevant events, schedule execution on different threads (or even different machines!), and the code remains as simple as if it was sequentially executed.

协程提供了一种避免阻塞线程并用更廉价、更可控的操作替代线程阻塞的方法:协程挂起。
协程通过将复杂性放入库来简化异步编程。程序的逻辑可以在协程中顺序地表达,而底层库会为我们解决其异步性。该库可以将用户代码的相关部分包装为回调、订阅相关事件、在不同线程(甚至不同机器!)上调度执行,而代码则保持如同顺序执行一样简单。

协程的官方使用说明

自己写了个请求网络的协程demo

1
2
3
4
5
6
7
8
9
// Your first coroutine
private fun oneCoroutine() {
launch { // launch new coroutine
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
println("Hello,") // main function continues while coroutine is delayed
Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}
1
2
3
4
5
6
7
8
9
10
11
// Bridging blocking and non-blocking worlds
private fun twoCoroutine() = runBlocking<Unit> {
// start main coroutine
launch {
// launch new coroutine
delay(1000L)
println("World!")
}
println("Hello,") // main coroutine continues while child is delayed
delay(2000L) // non-blocking delay for 2 seconds to keep JVM alive
}
1
2
3
4
5
6
7
8
9
10
11

// Waiting for a job
private fun threeCoroutine() = runBlocking {
val job = launch {
// launch new coroutine and keep a reference to its Job
delay(1000L)
println("World!")
}
println("Hello,")
job.join() // wait until child coroutine completes
}
1
2
3
4
5
6
7
8
9
10
11
12
// Extract function refactoring
private fun fourCoroutine() = runBlocking {
val job = launch { doWorld() }
"Hello,".println()
job.join()
}

// this is your first suspending function
suspend fun doWorld() {
delay(1000L)
println("World!")
}
1
2
3
4
5
6
7
8
9
10
11
// Coroutines ARE light-weight
private fun fiveCoroutine() = runBlocking<Unit> {
val jobs = List(10) { // launch a lot of coroutines and list their jobs
launch {
print("${it}___")
delay(1000L)
print("$it.")
}
}
jobs.forEach { it.join() } // wait for all jobs to complete
}
1
2
3
4
5
6
7
8
9
10
11

// Coroutine are like daemon threads
private fun sixCoroutine() = runBlocking {
launch {
repeat(1000) {
"I'm sleeping $it ...".println()
delay(500L)
}
}
delay(10_000L)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

// Cancelling coroutine execution
private fun cancelCoroutine() = runBlocking {
val job = launch {
repeat(1000) {
"I'm sleeping $it ...".println()
delay(500L)
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin()
println("main: Now I can quit.")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

// Cancellation is cooperative
private fun cancellationCoroutine() = runBlocking {
val startTime = System.currentTimeMillis()
val job = launch {
var nextPrintTime = startTime
var i = 0
while (i < 5) { // computation loop, just wastes CPU
// print a message twice a second
if (System.currentTimeMillis() >= nextPrintTime) {
println("I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1400L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
println("main: Now I can quit.")
}