CSP 模型详解

CSP 是 Go 并发模型背后的理论基础之一。

全称:

Communicating Sequential Processes

通信顺序进程

由英国计算机科学家
Tony Hoare
于 1978 年提出。


CSP 到底在解决什么问题

先看传统并发模型。

多个线程共享数据:

Thread1 ─┐
Thread2 ─┼── Shared Memory
Thread3 ─┘

大家都能修改同一块内存。

于是必须:

Mutex
RWMutex
Semaphore

来保证安全。

这种模式叫:

Shared Memory Concurrency(共享内存并发)


CSP 的想法完全不同:

Process A  ←→ Channel ←→ Process B

每个 Process(进程/协程)拥有自己的状态。

彼此不直接访问对方的数据。

通过消息通信协作。


一个现实例子

共享内存模式

公司里有一本账本:

余额 = 1000

所有员工都能直接改:

张三 +100
李四 -50
王五 +200

为了避免冲突:

先加锁
再修改
释放锁

CSP 模式

只有财务能改账本:

财务拥有账本

其他人:

发送申请

"帮我存100"
"帮我取50"

财务依次处理:

消息1
消息2
消息3

因此:

没有人直接碰账本

这就是 CSP 的核心思想。


Go 是怎么体现 CSP 的

Go 的两个核心组件:

go func() {}

创建执行单元。

ch := make(chan int)

创建通信通道。


例如:

ch := make(chan string)

go func() {
    ch <- "hello"
}()

msg := <-ch
fmt.Println(msg)

这里:

Goroutine A
   Channel
Goroutine B

A 和 B 不共享变量。

只交换消息。

这就是 CSP。


CSP 的核心原则

可以概括为三句话:

1. 数据有所有者

例如:

balance := 1000

只有某个 Goroutine 能修改。


2. 不直接访问别人的数据

不要:

other.balance += 100

而是:

depositCh <- 100

发送请求。


3. 用消息协作

不是:

共享变量
竞争

而是:

消息
Channel
事件流

Go 为什么适合 CSP

因为 Channel 是语言级特性。

例如:

select {
case msg := <-ch1:
    fmt.Println(msg)

case msg := <-ch2:
    fmt.Println(msg)
}

天然支持:

  • 消息传递

  • 多路复用

  • 超时控制

  • 取消机制

这比很多语言依赖第三方库实现 Actor/CSP 更自然。


CSP 和 Actor 模型的区别

有时会延伸问。

Actor(如 Erlang、Akka):

Actor A
Actor B
Actor C

特点:

  • 每个 Actor 有邮箱(Mailbox)

  • 通过消息通信

  • Actor 地址可寻址


CSP:

Process A
 Channel
Process B

特点:

  • Channel 是一等公民

  • 进程通过 Channel 建立连接

  • 通信路径显式

简单理解:

Actor:
找到人再发消息

CSP:
找到管道再通信

Go 真的完全遵循 CSP 吗

实际上:

不是。

Go 借鉴了 CSP,但不是纯 CSP。

因为 Go 同时支持:

sync.Mutex
sync.RWMutex
sync.Atomic

例如:

var mu sync.Mutex

这明显属于:

Shared Memory

而不是 CSP。

所以更准确地说:

Go 的并发设计理念受 CSP 影响,鼓励使用 Channel 和 Goroutine 进行通信,但在工程实践中同时提供共享内存和锁机制作为补充。


回答模板

如果官问:

什么是 CSP?Go 为什么说自己是 CSP 风格?

可以回答:

CSP(Communicating Sequential Processes)是一种并发模型,其核心思想是让并发执行单元通过消息通信协作,而不是直接共享数据。Go 的 Goroutine 对应 CSP 中的 Process,Channel 对应通信通道。Go 鼓励由一个 Goroutine 持有数据,其他 Goroutine 通过 Channel 发送消息进行交互,从而减少锁竞争和竞态问题。不过 Go 并不是纯 CSP,它也提供 Mutex、RWMutex 和 Atomic 等共享内存并发工具,因此更准确地说 Go 是一种受 CSP 思想影响的并发语言。