协程(Coroutine)作为轻量级线程的解决方案,在现代编程中扮演着越来越重要的角色。与传统线程相比,协程最大的特点是可以在单个线程内实现多任务的协作式调度,避免了线程切换的开销。我在实际项目中使用协程处理IO密集型任务时,实测性能提升可达3-5倍,而内存消耗仅为线程方案的1/10。
理解协程需要把握三个核心特性:
重要提示:协程不是银弹,CPU密集型任务仍建议使用线程池。我在电商项目中将商品详情页的IO操作(数据库查询+缓存读取+外部API调用)改用协程后,接口响应时间从120ms降至40ms。
协程上下文(CoroutineContext)本质上是各种元素的集合,这些元素定义了协程的执行环境。通过分析Kotlin协程库源码,我发现其核心实现实际是一个类型安全的异构容器:
kotlin复制public interface CoroutineContext {
operator fun <E : Element> get(key: Key<E>): E?
fun <R> fold(initial: R, operation: (R, Element) -> R): R
operator fun plus(context: CoroutineContext): CoroutineContext
//...
}
实际开发中最常用的上下文元素包括:
新建协程时,上下文会遵循明确的继承规则:
+运算符组合kotlin复制val parentJob = Job()
val scope = CoroutineScope(Dispatchers.IO + parentJob + CoroutineName("Parent"))
// 子协程会继承IO调度器、父Job和名称上下文
scope.launch {
// 这里可以通过coroutineContext获取完整上下文
println(coroutineContext[CoroutineName]) // 输出"Parent"
}
踩坑记录:在Android开发中,我曾因未正确管理上下文导致内存泄漏。正确的做法是在Activity的onDestroy中取消根Job:
parentJob.cancel()
Job作为协程生命周期的管理者,其内部实现是典型的状态机。通过调试Kotlin协程源码,我梳理出完整的状态转换路径:
code复制New (新建) → Active (活跃)
→ Completing (完成中) → Completed (已完成)
→ Cancelling (取消中) → Cancelled (已取消)
每个状态都有明确的语义:
1. 结构化并发的最佳实践
kotlin复制suspend fun fetchUserData() = coroutineScope {
val userProfile = async { fetchProfile() }
val userOrders = async { fetchOrders() }
UserData(
profile = userProfile.await(),
orders = userOrders.await()
)
}
这种模式确保所有子协程完成前父协程不会结束,避免资源泄漏。
2. 精细化取消控制
kotlin复制val job = launch {
try {
longRunningTask()
} finally {
if (isActive) {
// 正常结束逻辑
} else {
// 取消时的清理逻辑
withContext(NonCancellable) {
releaseResources()
}
}
}
}
// 需要取消时
job.cancel("Operation timeout")
3. 超时处理的正确姿势
kotlin复制val result = withTimeoutOrNull(3000) {
networkRequest()
} ?: run {
log("Request timeout")
defaultResponse()
}
在微服务架构中,我们需要跨协程传递追踪ID等上下文信息。通过自定义上下文元素可以实现:
kotlin复制class TraceContext(val traceId: String) : AbstractCoroutineContextElement(TraceContext) {
companion object Key : CoroutineContext.Key<TraceContext>
}
fun startRequest() {
val traceId = generateTraceId()
CoroutineScope(Dispatchers.IO + TraceContext(traceId)).launch {
serviceCall()
}
}
suspend fun serviceCall() {
val traceId = coroutineContext[TraceContext]?.traceId
?: throw IllegalStateException("Missing trace context")
// 使用traceId进行日志追踪
}
协程的异常处理遵循特定规则:
正确的异常处理模板:
kotlin复制val handler = CoroutineExceptionHandler { _, exception ->
sentry.capture(exception)
}
val scope = CoroutineScope(SupervisorJob() + handler)
scope.launch {
// 协程1
}
scope.launch {
// 协程2
}
通过反射获取内部计数器可以检测潜在的协程泄漏:
kotlin复制fun checkCoroutineLeak() {
val klass = Class.forName("kotlinx.coroutines.debug.internal.DebugProbesImpl")
val instance = klass.getDeclaredMethod("instance").invoke(null)
val coroutines = klass.getDeclaredMethod("dumpCoroutinesInfo")
.invoke(instance) as List<*>
if (coroutines.isNotEmpty()) {
coroutines.forEach { println(it) }
throw IllegalStateException("${coroutines.size} coroutines leaked!")
}
}
根据业务特点选择合适的调度器:
kotlin复制// 创建针对数据库操作的专用调度器
val dbDispatcher = Executors.newFixedThreadPool(10)
.asCoroutineDispatcher()
// 使用后必须手动关闭
runtime.addShutdownHook {
dbDispatcher.close()
}
kotlin复制System.setProperty("kotlinx.coroutines.debug", "on")
kotlin复制fun currentCoroutineInfo(): String {
val coroutine = Thread.currentThread().stackTrace
.first { it.className.startsWith("kotlinx.coroutines") }
return "${coroutine.methodName}@${coroutine.lineNumber}"
}
将协程与Flow结合实现复杂数据流处理:
kotlin复制fun observeUserActions(): Flow<Action> = callbackFlow {
val callback = object : ActionCallback {
override fun onAction(action: Action) {
trySend(action)
}
}
registerCallback(callback)
awaitClose { unregisterCallback(callback) }
}
fun analyzeActions() = launch {
observeUserActions()
.buffer(100) // 背压处理
.filter { it.type == IMPORTANT }
.map { transformAction(it) }
.collect { processFinalAction(it) }
}
通过协程实现全异步Controller:
kotlin复制@RestController
class UserController(private val service: UserService) {
@GetMapping("/users/{id}")
suspend fun getUser(@PathVariable id: Long): User {
return service.findUser(id)
}
@GetMapping("/users")
suspend fun listUsers(): Flow<User> {
return service.streamAllUsers()
}
}
配置Reactor上下文与协程上下文转换:
kotlin复制suspend fun <T> Mono<T>.await(): T = coroutineScope {
val deferred = async(Dispatchers.Unconfined) {
awaitSingleOrNull()
}
deferred.await() ?: throw NoSuchElementException()
}
在共享模块中定义协程公共逻辑:
kotlin复制expect val applicationDispatcher: CoroutineDispatcher
class GreetingService {
suspend fun greet(name: String): String {
return withContext(applicationDispatcher) {
"Hello, $name from ${Platform().platformName}"
}
}
}
在Android端的实现:
kotlin复制actual val applicationDispatcher: CoroutineDispatcher = Dispatchers.Main
在iOS端的实现:
kotlin复制actual val applicationDispatcher: CoroutineDispatcher =
MainLoopDispatcher()
在Node.js中使用协程处理异步IO:
kotlin复制suspend fun readFile(path: String): String {
return promise { resolve, reject ->
fs.readFile(path, "utf-8") { err, data ->
if (err != null) reject(err) else resolve(data as String)
}
}.await()
}
前端应用中的使用示例:
kotlin复制suspend fun loadUserData(): User {
val response = window.fetch("/api/user").await()
return response.json().await()
}
launch {
try {
val user = loadUserData()
renderUserProfile(user)
} catch (e: Exception) {
showErrorToast(e.message)
}
}