目录
什么是线程(Thread)?
线程与进程之间的关系
线程调度与并发执行
并发(Concurrency)与并行(Parallelism)
多线程编程的四大核心优势(benefits of multithreaded programming)
1️⃣ 响应性(Responsiveness)
2️⃣ 资源共享(Resource Sharing)
3️⃣ 经济性(Economy)
4️⃣ 多核架构的利用(Utilization of Multiprocessor Architectures)
什么是线程(Thread)?
在操作系统中,线程(Thread)是程序执行的最小单位。也就是说,线程是 CPU 实际调度和执行的基本单元。
所以,从 CPU 的角度看,它不是在执行“程序”,也不是在执行“进程”,而是在执行一个个线程。
线程的组成部分
每个线程在运行时,需要具备一定的执行上下文(execution context)。一个线程通常由以下几部分组成:
组成部分 | 作用 |
---|---|
Thread ID | 操作系统为每个线程分配的唯一编号,用于标识和管理线程 |
Program Counter(程序计数器) | 当前线程将要执行的下一条指令的地址 |
Register Set(寄存器集合) | 包括通用寄存器、堆栈指针、程序状态字等,用于存储线程的运行状态 |
Stack(栈) | 每个线程都有自己的栈空间,用于存储函数调用、返回地址、局部变量等 |
这些是线程私有的,每个线程都要拥有自己的这些资源,才能独立运行。
线程与进程之间的关系
进程(Process)是一个正在运行的程序实例,它是操作系统资源分配的最基本单位。一个进程拥有:
-
独立的地址空间(虚拟内存)
-
独立的代码段、数据段、堆和栈
-
文件描述符等系统资源
所以,一个传统的进程只包含一个线程,也叫“单线程进程”。
具体关于进程的介绍可以参考:操作系统:进程管理(Process Management)-CSDN博客
那么,线程与进程的关系是什么?
可以这样理解:
-
一个线程是属于某个进程的
-
一个进程可以包含一个或多个线程
-
一个进程中的所有线程共享该进程的资源
线程共享的内容包括:
共享内容 | 描述 |
---|---|
代码段(Code Section) | 所有线程执行的程序指令是一样的 |
数据段(Data Section) | 包括全局变量、静态变量等 |
堆(Heap) | 动态分配的内存区域 |
打开的文件描述符 | 所有线程可以访问同一组文件、socket 等 |
换句话说,线程是在同一个进程中运行的多个控制流(control flow)。
线程调度与并发执行
线程是操作系统调度的单位。每当 CPU 需要切换任务,它可以在不同线程之间切换,形成并发执行的效果。
如果一个程序只有一个线程:
程序中的所有任务只能串行(sequential)执行,一件事做完,才能做下一件。
如果一个程序有多个线程:
多个线程可以并发执行,每个线程负责一部分任务,比如:
-
一个线程负责接收用户输入
-
一个线程负责处理后台计算
-
一个线程负责保存文件
这样,程序就可以显得“更快”“更流畅”。如果只有一个线程,那么当用户在输入时,下载任务等就会被迫停止。
在多核 CPU 上,多个线程甚至可以真正同时执行(并行 execution)。
并发(Concurrency)与并行(Parallelism)
并发(Concurrency)
核心思想:在同一时间段里处理多个任务,但不一定真的在“同一时刻”运行。
-
系统快速切换任务,让它们看起来像是同时进行的。
-
适合处理大量独立或部分交互的任务,重点在管理任务。
形象比喻:
你只有一个厨师,要做三道菜。厨师会炒一会儿菜A,等水开时去切菜B,再回来煮菜C,看起来三道菜都在同时进行,但实际上厨师一次只做一件事——只是切换得足够快。
技术特征:
-
常出现在单核CPU + 多任务调度中。
-
线程或进程可能共享CPU时间片(time slice)。
-
重点是任务切换(context switching)。
并行(Parallelism)
核心思想:在同一时刻真正执行多个任务,需要多个处理单元(多核CPU、多台机器等)。
-
每个任务都占用独立的处理资源,同时推进。
-
重点在加快计算速度。
形象比喻:
你有三个厨师,每个人负责一道菜,大家同时动手,三道菜能一起完成。
技术特征:
-
常出现在多核CPU、GPU、分布式计算中。
-
线程或进程在不同核心上同时运行。
-
强调硬件并行能力。
并发 vs 并行 —— 关键区别
特性 | 并发(Concurrency) | 并行(Parallelism) |
---|---|---|
定义 | 管理多个任务的执行顺序,使它们“看起来”同时进行 | 多个任务真的同时执行 |
硬件需求 | 不一定需要多核 | 需要多核或多CPU |
实现方式 | 时间片轮转、异步 I/O | 多核调度、向量化计算 |
目标 | 提高资源利用率、响应性 | 缩短执行时间 |
例子 | 单核CPU运行多线程Web服务器 | GPU同时计算成千上万个像素 |
结合关系
-
并发是一个编程与调度思想,它不一定要依赖硬件多核,但可以在多核环境下跑得更快。
-
并行是一个硬件执行层面的能力,需要多个处理单元才能实现。
-
两者的关系可以这样总结:
并发 = 会做很多事(安排得开)
并行 = 同时做很多事(人手够多)
实际应用中的区别
-
Web服务器:一个单核服务器通过并发(异步I/O)也能同时处理成千上万个请求,但它一次只能用CPU处理一个任务。
-
科学计算:并行化矩阵乘法时,每个CPU核心同时计算矩阵不同部分,大幅减少总时间。
-
游戏引擎:既用并发(管理用户输入、AI、物理计算等任务),也用并行(多核同时渲染不同画面部分)。
多线程编程的四大核心优势(benefits of multithreaded programming)
多线程编程的四大核心好处
分类 | 中文名称 | 简要概括 |
---|---|---|
Responsiveness | 响应性 | 线程分工协作,避免程序“卡死” |
Resource Sharing | 资源共享 | 多线程天然共享内存资源 |
Economy | 资源经济性 | 线程创建和切换成本比进程低 |
Utilization of Multiprocessors | 多核处理器利用率 | 多线程可在多核 CPU 上真正并行运行 |
下面我们一项一项详细解释。
1️⃣ 响应性(Responsiveness)
在一个交互式应用程序中(例如图形界面、浏览器、游戏),有些操作可能需要较长时间,例如:
-
加载大文件;
-
下载网络资源;
-
进行复杂计算(比如渲染、解压缩)。
如果这些任务由主线程(主控制流)执行,用户界面将冻结或卡住,导致用户体验极差。
多线程的好处:
通过将耗时操作放入后台线程执行,主线程仍然能接收用户输入,界面保持响应。
举例说明:
-
在一个 Word 编辑器中,主线程负责响应键盘输入;
-
后台线程负责保存、拼写检查、自动备份;
-
即使备份正在进行,你依然可以输入文字。
2️⃣ 资源共享(Resource Sharing)
同一进程内的所有线程共享代码、数据、内存空间和操作系统资源(如打开的文件、套接字)。
这和进程之间数据隔离的情况不同 —— 进程之间要通信,通常要使用 IPC(进程间通信机制)。
多线程的好处:
-
数据可以直接共享,不需要复制;
-
通信无需借助复杂机制(如管道、共享内存、消息队列);
-
更容易开发结构清晰的协同模块。
举例说明:
-
浏览器的多个标签页可能是一个进程内的多个线程;
-
所有线程共享缓存、网络连接、内存;
-
不需要在标签页之间“传递数据” —— 它们天然就在同一个地址空间里。
3️⃣ 经济性(Economy)
创建一个线程比创建一个进程更加轻量(经济):
操作 | 资源消耗 |
---|---|
创建新进程 | 分配独立地址空间、内存映射、文件表复制等,代价高 |
创建新线程 | 只需分配一个新的栈空间,复用现有进程资源,开销小 |
此外,线程之间的上下文切换(context switch)也比进程快得多。因为它们在同一个进程中,不涉及地址空间切换。
多线程的好处:
-
更快的启动速度;
-
更少的内存占用;
-
更高的执行效率。
举例说明:
-
一个下载器开启 10 个线程同时下载 10 个文件;
-
如果是 10 个进程,系统将为每个进程分配内存、创建文件描述符,开销更大;
-
使用 10 个线程则只需一份代码和资源。
4️⃣ 多核架构的利用(Utilization of Multiprocessor Architectures)
现代计算机几乎都拥有多核 CPU(如 4 核、8 核甚至更多);
-
一个单线程程序始终只能在一个 CPU 核上运行;
-
而多线程程序中的多个线程可以被操作系统同时分配到多个核心上。
多线程的好处:
-
真正的并行计算;
-
提高程序的整体吞吐量;
-
充分利用硬件资源,尤其在高性能场景(如图像处理、科学计算)中收益巨大。
举例说明:
你写了一个程序,需要对 1000 张图片同时做缩放处理:
-
单线程:一张一张顺序处理;
-
多线程:开启 8 个线程,8 核 CPU 每个线程各自处理一部分图片,速度提升近 8 倍。