92 lines
4.0 KiB
Markdown
92 lines
4.0 KiB
Markdown
---
|
|
tags: [go, golang, 并发概述, CSP]
|
|
create time: 2026-06-07 14:30
|
|
---
|
|
|
|
# 并发概述
|
|
|
|
## 概述
|
|
|
|
本文梳理进程、线程、协程的核心概念,区分"并发"与"并行"的本质差异,为后续深入 Go 的并发编程(Goroutine / Channel / Sync)奠定理论基础。
|
|
|
|
## 正文
|
|
|
|
### 进程与线程
|
|
|
|
> [!question] 💭 思考
|
|
> 一个正在运行的程序,操作系统需要分配哪些资源来支撑它?如果多个程序同时运行,它们之间如何互不干扰?
|
|
|
|
**进程**是操作系统分配资源的基本单位。它是程序在操作系统上的一次执行过程——注意,这里是"执行过程"而非"程序本身",强调的是动态性。
|
|
|
|
**线程**是 CPU 调度的基本单位,是进程中实际执行任务的实体。
|
|
|
|
| 维度 | 进程 | 线程 |
|
|
|------|------|------|
|
|
| 角色 | 资源分配单位 | CPU 调度单位 |
|
|
| 开销 | 大(独立地址空间) | 小(共享父进程内存) |
|
|
| 隔离性 | 强(进程间需 IPC) | 弱(共享同一进程内存) |
|
|
|
|
> [!warning] ⚠️ 常见误区
|
|
> "进程 = 重型,线程 = 轻型"——这并不准确。关键区别在于:**进程有独立地址空间,线程共享地址空间**。这也意味着线程间数据共享方便,但更容易出现竞态条件。
|
|
|
|
```mermaid
|
|
graph LR
|
|
P["进程 Process"] --> T1["线程 Thread 1"]
|
|
P --> T2["线程 Thread 2"]
|
|
P --> T3["线程 Thread 3"]
|
|
style P fill:#e1f5fe
|
|
```
|
|
|
|
一个进程可以包含多个线程,它们共享堆空间和文件描述符,但各自拥有独立的栈空间和寄存器状态。
|
|
|
|
### 协程
|
|
|
|
> [!question] 💭 思考
|
|
> 如果线程的创建和切换需要操作系统参与(陷入内核态),有没有一种更轻量的方式来实现并发?
|
|
|
|
**协程**是用户态线程,由应用程序自己管理调度,不需要操作系统参与。
|
|
|
|
| 对比项 | 线程 | 协程 |
|
|
|--------|------|------|
|
|
| 调度位置 | 内核态(OS 调度) | 用户态(语言运行时调度) |
|
|
| 切换开销 | 高(涉及上下文切换) | 低(仅保存/恢复栈指针) |
|
|
| 典型实现 | OS pthread / CreateThread | Go goroutine / Python asyncio |
|
|
|
|
Go 语言的 Goroutine 就是协程的典型实现——它由 Go 运行时(runtime)在自己的 GMP 调度器下管理,而不是直接映射到 OS 线程。
|
|
|
|
> [!tip] 💡 技巧
|
|
> 一个进程可以有多个线程,一个线程可以有多个协程。这意味着协程比线程更轻量:你可以轻松创建数十万个 goroutine,但开数十万个线程几乎必然耗尽系统资源。
|
|
|
|
### 并发与并行
|
|
|
|
> [!question] 💭 思考
|
|
> 单核 CPU 上能实现"同时执行"吗?如果能,那"同时"是什么意思?
|
|
|
|
这两个概念经常被混用,区分的关键只有一点:**能不能真正同时执行**。
|
|
|
|
- **并行(Parallelism)**:多个任务在同一时刻真正同时在多个核心上执行。必须有多个 CPU 核心支持。
|
|
- **并发(Concurrency)**:多个任务交替执行,每个任务执行一小段时间片后让出 CPU,宏观上看起来像"同时"在进行。单核 CPU 也能做到。
|
|
|
|
```mermaid
|
|
timeline
|
|
title 并行 vs 并发
|
|
section 并行 (多核)
|
|
Task A : 执行 : 执行 : 执行
|
|
Task B : 执行 : 执行 : 执行
|
|
section 并发 (单核)
|
|
Task A : 执行1 : 空闲 : 执行3
|
|
Task B : 空闲 : 执行2 : 空闲
|
|
```
|
|
|
|
如图所示:
|
|
- **并行**模式下,Task A 和 Task B 在每个时间段都在同时运行——这需要多核 CPU 的支持。
|
|
- **并发**模式下,两个任务轮流使用 CPU,每次只执行一小段,交叉进行——这在单核 CPU 上即可完成。
|
|
|
|
> [!note] 📝 关系总结
|
|
> 并行一定是并发(因为并行也满足"交替执行"的广义定义),但并发不一定是并行。Go 的并发模型可以在单核上运行,也可以利用多核实现真正的并行——这取决于 `GOMAXPROCS` 的设置。
|
|
|
|
## 关联笔记
|
|
|
|
- [[hzh/GolangStar/Go语言进阶/Goroutine]]
|
|
- [[hzh/GolangStar/Go语言原理/gmp调度原理]]
|