Files
cs-note/hzh/GolangStar/Go语言进阶/并发概述.md
T

4.0 KiB
Raw Blame History

tags, create time
tags create time
go
golang
并发概述
CSP
2026-06-07 14:30

并发概述

概述

本文梳理进程、线程、协程的核心概念,区分"并发"与"并行"的本质差异,为后续深入 Go 的并发编程(Goroutine / Channel / Sync)奠定理论基础。

正文

进程与线程

[!question] 💭 思考 一个正在运行的程序,操作系统需要分配哪些资源来支撑它?如果多个程序同时运行,它们之间如何互不干扰?

进程是操作系统分配资源的基本单位。它是程序在操作系统上的一次执行过程——注意,这里是"执行过程"而非"程序本身",强调的是动态性。

线程是 CPU 调度的基本单位,是进程中实际执行任务的实体。

维度 进程 线程
角色 资源分配单位 CPU 调度单位
开销 大(独立地址空间) 小(共享父进程内存)
隔离性 强(进程间需 IPC) 弱(共享同一进程内存)

[!warning] ⚠️ 常见误区 "进程 = 重型,线程 = 轻型"——这并不准确。关键区别在于:进程有独立地址空间,线程共享地址空间。这也意味着线程间数据共享方便,但更容易出现竞态条件。

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 也能做到。
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 的设置。

关联笔记