结构化并发(Structured Concurrency)是一种编程范式,旨在通过明确的生命周期管理和层次化的任务组织,确保并发操作(如线程、协程等)的可控性和可维护性。
它的核心思想是:并发任务应该像结构化编程中的代码块一样,具有清晰的开始和结束,并且父任务必须等待所有子任务完成才能结束。
一、结构化并发的核心原则
1. 生命周期绑定
- 所有的并发任务(如协程)都必须在一个明确的作用域(Scope)内启动。
- 子任务的生命周期不能超过父任务的生命周期。父任务必须等待所有子任务完成后才能结束。
2. 错误传播
- 如果子任务发生错误,错误会向上传播到父任务,确保错误不会被忽略。
- 这种机制类似于结构化编程中的异常处理。
3. 资源管理
- 结构化并发确保所有资源(如线程、内存等)在任务完成后被正确释放,避免资源泄漏。
4. 任务层次化
- 并发任务以树状结构组织,父任务可以启动多个子任务,但父任务的生命周期由最慢的子任务决定。
二、结构化并发的优势
- 避免任务泄漏:确保所有任务都能被正确跟踪和完成,不会出现“丢失”的任务。
- 简化错误处理:通过错误传播机制,开发者可以更容易地处理并发任务中的异常。
- 清晰的代码结构:任务的生命周期和作用域明确,代码更易于理解和维护。
- 资源安全:确保所有资源在任务完成后被释放,避免内存泄漏等问题。
三、 结构化并发的实现
在 Kotlin 协程中,结构化并发通过 `CoroutineScope` 实现。每个协程都必须在一个 CoroutineScope 中启动,而 `CoroutineScope` 的生命周期决定了其中所有协程的生命周期。例如:
import kotlinx.coroutines.*
fun main() = runBlocking { // 创建一个顶层协程作用域
launch { // 在 runBlocking 的作用域内启动一个新协程
delay(1000)
println("World!")
}
println("Hello,")
}
在这个例子中:
- runBlocking 创建了一个协程作用域。
- launch 启动的子协程的生命周期受限于 `runBlocking` 的作用域。
- runBlocking 会等待其所有子协程完成后才退出。
四、 结构化并发与其他并发模型的对比
- 非结构化并发:任务可以随意启动,生命周期不受约束,容易导致任务泄漏和资源管理困难。
- 结构化并发:通过作用域和层次化任务管理,确保任务的生命周期可控,资源管理更安全。
总结来说,结构化并发是一种更安全、更可控的并发编程方式,特别适合现代异步编程场景(如 Kotlin 协程)。它通过明确的作用域和任务层次化,解决了传统并发编程中的常见问题,如任务泄漏、错误丢失和资源管理困难。
五、并发管理
1、切线程
2、线程同步——多个线程间的等待
3、线程安全——互斥锁