Skip to content

CSP 模型详解 ​

1. CSP 模型简介 ​

CSP(Communicating Sequential Processes,通信顺序进程)是一种并发编程模型,由英国数学家 Tony Hoare 于1978年提出。它主张用进程间的消息传递代替共享内存来组织并发。Go 里的 goroutine 和 channel 就是 CSP 模型的落地。

CSP 把并发执行单位抽象成进程(Process),进程之间靠通信通道(Channel)传消息,不共享内存。

2. CSP 模型的组成部分 ​

  1. 进程(Process):独立执行的并发实体,类似于线程或协程。每个进程独立执行自己的代码。
  2. 通信通道(Channel):进程之间进行消息传递的媒介。通过通道,进程可以发送和接收消息,实现同步或异步通信。

3. CSP 模型的工作流程 ​

先创建新进程拿到并发,之后的交互只有两种动作:发送方把消息写进通道,接收方从通道里读出来。读写可以是同步的,双方就绪才完成;也可以走带缓冲的通道,发送方不等接收方。

4. CSP 模型的优缺点 ​

优点:

  • 模型直观:通信发生在通道两端,读代码时顺着通道找得到收发双方。
  • 不用共享内存和锁,避免了共享内存带来的竞争条件和死锁问题。
  • 通道的抽象不受进程边界限制,换成网络通信就能扩到分布式场景。

缺点:

  • 消息要拷贝、要调度,频繁传递有开销。
  • 吞吐要求高的场景里,这个开销会成为瓶颈。

5. CSP 模型的应用场景 ​

  • 高并发系统:如网络服务器、实时数据处理系统。
  • 事件驱动系统:如 GUI 事件处理、异步任务调度。
  • 分布式系统:通过网络通信实现分布式计算。

6. CSP 模型的示例 ​

一个用 channel 分发任务的 Go 示例:

go
package main

import (
	"fmt"
	"time"
)

// worker 函数,模拟一个并发任务
func worker(id int, jobs <-chan int, results chan<- int) {
	for j := range jobs {
		fmt.Printf("Worker %d started job %d\n", id, j)
		time.Sleep(time.Second) // 模拟工作时间
		fmt.Printf("Worker %d finished job %d\n", id, j)
		results <- j * 2 // 返回结果
	}
}

func main() {
	const numJobs = 5
	jobs := make(chan int, numJobs)
	results := make(chan int, numJobs)

	// 启动3个 worker goroutine
	for w := 1; w <= 3; w++ {
		go worker(w, jobs, results)
	}

	// 发送5个任务
	for j := 1; j <= numJobs; j++ {
		jobs <- j
	}
	close(jobs)

	// 收集结果
	for a := 1; a <= numJobs; a++ {
		<-results
	}
}

示例启动 3 个 worker goroutine 处理 5 个任务:任务经 jobs 通道下发,worker 取到任务处理完把结果写进 results,主程序收满 5 个结果后退出。

7. CSP 模型与其他并发模型的比较 ​

  • 与 Actor 模型:CSP 模型强调通过通道传递消息,而 Actor 模型强调通过消息传递和独立的 Actor 实体来实现并发。CSP 更加简洁和直接,适合进程之间的通信,而 Actor 模型则更加灵活,适合复杂的并发和分布式系统。
  • 与线程模型:传统的线程模型使用锁和共享状态来实现并发,容易出现死锁和竞争条件。CSP 模型通过消息传递避免了这些问题,实现了安全且简单的并发编程。

8. 结论 ​

CSP 把并发单位和通信媒介拆成两样东西,Go 用 goroutine 和 channel 实现了它。写并发程序时,先把数据流画成"谁发、谁收",再决定开几个 goroutine。

参考资料 ​

相关页面 ​

Hello Golang