协程有两个启动函数:launch 和 async,但它们都是并行启动协程的。实际上协程还提供了一个特殊的启动协程的函数 runBlocking:

// 1. 不需要 CoroutineScope 启动协程
runBlocking {
	// 2. 执行的协程代码会阻塞住当前线程,直到 runBlocking 执行结束
}

runBlocking 有两个特殊点:

  • 它不需要 CoroutineScope

  • runBlocking 会阻塞当前线程,直到 runBlocking 的代码都执行结束才会继续执行后续代码

我们对它的特殊点一个个分析。

runBlocking-不需要 CoroutineScope

我们简单回顾下 CoroutineScope 的作用:

  • 它能提供很多协程需要的 CoroutineContext,比如 CoroutineScope 提供了 ContinuationInterceptor(即 Dispatchers.IO 或 Dispatchers.Default 等)让协程知道自己应该运行在什么线程

  • 它能提供后续对协程的取消

按 CoroutineScope 的功能分析,可以发现 runBlocking 不需要 CoroutineScope 是因为它既不需要上下文又不需要被取消,所以就不需要 CoroutineScope

runBlocking-会阻塞当前线程

runBlocking 的阻塞是线程级别的阻塞,只要它调用就会阻塞直到 runBlocking 里面的代码执行完毕

runBlocking 的定位是把挂起函数的代码转换成阻塞式代码,虽然 runBlocking 会启动一个协程,但 它的作用并不在于启动协程本身,而是在于把协程格式的代码封装起来变成阻塞式的,方便让传统的线程写法 API 使用

// 提供给传统的线程 API 使用
private fun blockingContributors() = runBlocking {
	// 挂起函数
	gitHub.contributors("square", "retrofit")
}

为什么需要将协程格式的代码封装成阻塞式的?假设有一种场景:已经用协程写好的库,但是它是用挂起函数写的,需要串行的在线程 API 去调用这个库,因为 launch 或 async 启动协程是并行的,这时候 runBlocking 就派上用场了。

总结

  • runBlocking 启动协程不需要 CoroutineScope 是因为它既不需要上下文又不需要被取消

  • runBlocking 的阻塞是线程级别的阻塞,它的定位是把挂起函数的代码转换成阻塞式代码,方便让传统的线程写法 API 使用

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐