CSP(Communicating Sequential Processes)并发模型
CSP 模型的核心思想是 “不要通过共享内存来通信,而是通过通信来共享内存” 。 Go 通过 goroutine 和 channel 来实现 CSP 并发。
Goroutine(协程)
Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理,创建成本远低于系统线程。
go关键字用于启动新协程。- Goroutine 由 Go 运行时调度,而非 OS 线程,调度器会在多个线程上执行它们。
- Goroutine 是非阻塞的,主 Goroutine 可能会先退出,导致其他 Goroutine 也终止。
Channel(通道)
用于 Goroutine 之间的通信和数据同步。
无缓冲通道(同步)
- 无缓冲通道会阻塞 发送方,直到 接收方 读取数据。
带缓冲通道(异步)
- 发送数据到缓冲未满的通道时不会阻塞。
- 当通道满时,发送操作会阻塞,直到有 Goroutine 读取数据。 注:
- 关闭的通道不能再发送数据,否则会导致 panic。
- 读取已关闭通道的数据,若通道为空,则会返回零值。
WaitGroup(等待所有 Goroutine 完成)
sync.WaitGroup 用于等待多个 Goroutine 结束。
wg.Add(n)指定等待的任务数量。wg.Done()表示一个任务完成。wg.Wait()阻塞主 Goroutine,直到所有任务完成。
Context
context 在 Go 并发编程中主要用于 控制 Goroutine 的生命周期,严格来说,它并不完全属于 CSP 并发模型或共享内存并发模型,而是 一种协作取消机制,但它更符合 CSP 并发模型 的思想。
- 使用
context.WithTimeout实现超时广播。 - 使用
context.WithDeadline指定了一个绝对时间点,从而实现超时。 context.WithCancel()适用于手动触发广播,发送取消信号,所有 Goroutine 退出。
共享内存(Shared Memory)并发模型
共享内存模型的核心思想是 多个 Goroutine 通过访问同一个变量进行通信,并使用同步机制(如 互斥锁(Mutex) 或 读写锁(RWMutex) )来保证数据安全。
互斥锁
在并发环境下,多个 Goroutine 访问共享资源时需要同步,sync.Mutex 用于保证资源互斥访问。
mutex.Lock()互斥访问共享资源。mutex.Unlock()释放锁,避免死锁。
读写锁
sync.RWMutex 允许多个 Goroutine 同时读取,但 写入时必须互斥。
RLock()允许多个读操作同时进行。Lock()只允许一个写操作,写入时会阻塞所有读操作。
条件变量
sync.Cond 用于协调 Goroutine 之间的等待和唤醒。
cond.Wait()让 Goroutine 等待条件满足。cond.Broadcast()唤醒所有等待的 Goroutine。
原子操作
- 直接 修改共享变量,但保证操作的不可分割性(Atomicity)。
- 不使用锁,但仍然是 基于共享内存 的并发控制机制。
- 典型操作:
atomic.AddInt64(&count, 1)原子递增atomic.LoadInt64(&count)原子读取atomic.CompareAndSwapInt64(&value, old, new)原子 CAS
- 这些操作本质上都是 在共享内存上进行无锁同步。