跳到主要内容

Go 语言并发模型

为更好的编写并发程序,从设计之初 Go 语言就注重如何在编程语言层级上设计一个简洁安全高效的抽象模型,让程序员专注于分解问题和组合方案,而且不用被线程管理和信号互斥这些繁琐的操作分散精力。

因此,Go 语言提供了一种简单而强大的并发模型,主要是通过基于 CSP 的轻量级的 goroutine 和通道(channel)来实现,这使得它天生就支持并发编程。

CSP 模型

CSP 是 Communicating Sequential Processes 的缩写,即“通信顺序进程”。它是著名计算机科学家 C. A. R. Hoare 在上个世纪七十年代为解决并发现象而提出的代数理论,是专为描述并发系统中进程通信而设计的一种抽象语言。

严格来讲,CSP 是一门形式语言,用于描述并发系统中的互动模式。具体到编程语言中(如 Golang),CSP 具象化为一种并发编程模型,用于描述两个独立的并发实体通过共享的通讯(如 channel)进行通信的并发模型,CSP 理论中的 Process/Channel 对应到 Golang 中的 goroutine/channel。

在 CSP 模型中,Process 和 Channel 这两个并发原语之间没有从属关系,Process 可以订阅任意个 Channel,Channel 也并不关心是哪个 Process 在利用它进行通信;Process 围绕 Channel 进行读写,形成一套有序阻塞和可预测的并发模型。

基本概念

开始学习 Go 语言并发编程之前,我们先来了解 Go 语言并发模型相关的一些概念:

  • Goroutine(协程):goroutine 是 Go 语言中的一种轻量级线程,由 Go 运行时环境管理。每个 goroutine 都是一个独立的执行单元,可以并发地执行函数或方法。相比于传统的线程,goroutine 的创建和销毁成本更低,可以高效地使用系统资源。
  • 通道(Channel):通道是 goroutine 之间进行通信的一种方式,用于在不同 goroutine 之间传递数据。通道提供了一种同步的机制,确保数据安全地在 goroutine 之间传递。通道分为有缓冲通道和无缓冲通道,有缓冲通道允许在发送数据时不立即阻塞,而无缓冲通道则要求发送和接收操作同时准备好才能进行通信。
  • 并发(Concurrency):并发是指程序具有同时执行多个任务的能力。在 Go 语言中,可以使用 goroutine 来实现并发,每个 goroutine 可以独立执行不同的任务,从而实现高效的并发编程。
  • 同步(Synchronization):同步是指在并发编程中协调多个 goroutine 的执行顺序或状态的过程。在 Go 语言中,通道是一种常用的同步机制,通过通道的阻塞操作来实现 goroutine 之间的同步。
  • 互斥锁(Mutex):互斥锁是一种用于保护共享资源的同步机制,用于在多个 goroutine 之间提供互斥访问共享资源的能力。在 Go 语言中,可以使用 sync 包中的 Mutex 类型来实现互斥锁。
  • 条件变量(Condition Variable):条件变量是一种用于在多个 goroutine 之间进行线程间通信的同步机制。在 Go 语言中,可以使用 sync 包中的 Cond 类型来实现条件变量。
  • 原子操作(Atomic Operation):原子操作是一种不可被中断的操作,可以保证在多个 goroutine 之间对共享变量的读写操作是原子性的。在 Go 语言中,可以使用 sync/atomic 包提供的原子操作函数来实现原子操作。

并发与并行

需要特别指出,并发和并行是两个不同的概念。

  • 并发更关注的是程序的设计层面,并发的程序完全是可以顺序执行的,只有在真正的多核 CPU 上才可能真正地同时运行。
  • 并行更关注的是程序的运行层面,并行一般是简单的大量重复,例如 GPU 中对图像处理都会有大量的并行运算。

小结

总的来说,Go 语言的并发模型基于 goroutine(协程)和 channel(通道)实现,它提供了一种简单而强大的方式来实现并发编程。通过使用 goroutine、通道和其他同步机制,可以编写出安全、高效和可靠的并发程序。