【翻译】kotlin协程核心库文档(一)——|【翻译】kotlin协程核心库文档(一)—— 协程基础
github原文地址
原创翻译,转载请保留或注明出处:https://www.jianshu.com/p/7497bce754eb
协程基础 本小节涵盖了协程的基础概念
第一个协程
运行以下代码:
fun main(args: Array) {
launch { // launch new coroutine in background and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
println("Hello,") // main thread continues while coroutine is delayed
Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}
【【翻译】kotlin协程核心库文档(一)——|【翻译】kotlin协程核心库文档(一)—— 协程基础】获取完整代码 here运行结果:
Hello,
World!
实质上,协程是轻量级的线程。它们使用 “launch” 协程构建器启动 ,你也可以通过如下方式获得同样的结果:替换
launch { ... }
为thread { ... }
, 替换delay(...)
为 Thread.sleep(...)
。连接阻塞、非阻塞的世界
第一个示例混合了非阻塞的
delay(...)
与 阻塞的 Thread.sleep(...)
在同一块代码中。这很容易让人迷惑哪一处是阻塞的哪一处不是。我们可以通过使用 runBlocking 协程构建器来明确阻塞:fun main(args: Array) {
launch { // launch new coroutine in background and continue
delay(1000L)
println("World!")
}
println("Hello,") // main thread continues here immediately
runBlocking { // but this expression blocks the main thread
delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
}
}
获取完整代码 here结果是相同的,但是这段代码使用了非阻塞的delay。调用
runBlocking
的主线程阻塞了,直到内部协程runBlocking
完成。这个示例同样可以用一种更通顺的方式改写:使用
runBlocking
来封装主函数的执行:fun main(args: Array) = runBlocking { // start main coroutine
launch { // launch new coroutine in background and continue
delay(1000L)
println("World!")
}
println("Hello,") // main coroutine continues here immediately
delay(2000L) // delaying for 2 seconds to keep JVM alive
}
获取完整代码 here这里
runBlocking { ... }
作为一个适配器,用来启动顶层主协程。 我们明确地指定它的返回类型为Unit
,因为一个格式良好的Kotlin主函数必须返回 Unit
。这同样也是为挂起函数编写单元测试的一种方式:
class MyTest {
@Test
fun testMySuspendingFunction() = runBlocking {
// here we can use suspending functions using any assertion style that we like
}
}
等待一个任务
当另一个协程正在工作时,延迟一段时间并不是一个好的方式。我们可以通过明确地方式等待(以非阻塞的方式),直到我们之前启动的后台任务完成:
fun main(args: Array) = 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
}
获取完整代码 here现在结果是同样的,但是主协程的代码不以任何方式与后台任务的执行时间相关联。
提取函数进行重构
我们可以提取
launch { ... }
中的代码块到另一个分离的函数中。当你对这段代码进行“提取函数”重构时,你会得到一个带有 suspend
修饰符的新函数。这是你的第一个挂起函数。挂起函数可以像普通函数一样在协程中使用,但他们的附加功能是,他们可以反过来使用其他挂起函数。类似这个示例中的delay
,它挂起了一个协程的执行过程。fun main(args: Array) = runBlocking {
val job = launch { doWorld() }
println("Hello,")
job.join()
}// this is your first suspending function
suspend fun doWorld() {
delay(1000L)
println("World!")
}
获取完整代码 here协程是轻量的
执行以下代码:
fun main(args: Array) = runBlocking {
val jobs = List(100_000) { // launch a lot of coroutines and list their jobs
launch {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() } // wait for all jobs to complete
}
获取完整代码 here它启动了10万个协程,并在一秒后,每个协程打印了一个“.”。骚年,你敢用线程做这样的事么?(很可能你的代码会产生一些内存溢出的错误)。
协程类似守护线程
下面的代码启动了一个长时间运行的协程,它每秒打印两次“I'm sleeping”,在一段延迟后从主函数返回:
fun main(args: Array) = runBlocking {
launch {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
}
delay(1300L) // just quit after delay
}
获取完整代码 here你可以运行并看到它打印了三行然后终止:
I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...
激活的协程并不会使进程保持活跃状态,它们就像守护线程一样。
推荐阅读
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 20190302|20190302 复盘翻盘
- 学无止境,人生还很长