Review
A thread is a basic unit of CPU utilization.
Thread Concept
对比维度 | 进程 | 线程 |
---|---|---|
单元性质 | 独立执行单元,能独立执行任务,拥有独立资源集合 | 进程的子集,不能脱离进程单独存在,一个进程可含多个线程 |
状态信息 | 保存大量状态信息,如进程ID、状态、内存管理信息、文件描述符列表等 | 共享进程状态、内存和其他资源,仅维护线程ID、程序计数器、寄存器集合、栈空间等少量信息 |
地址空间 | 拥有独立的地址空间,不同进程地址空间相互隔离 | 共享所属进程的地址空间 |
通信方式 | 依赖进程间通信(IPC)机制,如管道、消息队列、共享内存、信号量等 | 除IPC机制外,还可通过共享内存直接通信 |
上下文切换 | 切换时需保存和恢复全部状态信息,涉及大量数据操作,开销大,速度相对较慢 | 仅需保存和恢复少量状态信息,且因共享地址空间无需切换内存管理信息,速度更快 |
pros:
- 多相似任务处理
- 利用多核系统
- 创建线程轻量化
examples:
- Client-server applications
- Most operating system kernels are multithreaded
Multicore Programming
对比维度 | Concurrency(并发) | Parallelism(并行) |
---|---|---|
核心定义 | 逻辑上“同时”处理多个任务,通过任务切换实现 | 物理上“同时”执行多个任务,依赖多核或分布式系统 |
实现方式 | 时间片轮询(如操作系统线程调度) 多线程、异步 I/O、事件循环,Web 服务器处理多个请求(如 Nginx) | 直接分配独立资源(如多核 CPU 或分布式节点) 多线程、多进程、GPU/TPU 加速、分布式计算,科学计算(如天气模拟)、图像处理(如 GPU 渲染) |
资源需求 | 低,单核 CPU 即可 | 高,需多核 CPU 或分布式系统 |
适用任务类型 | I/O 密集型(如数据库查询、网络请求) | 计算密集型(如矩阵运算、AI 训练) |
性能瓶颈 | 上下文切换开销、I/O 延迟 | 任务可拆分性、通信开销(分布式场景) |
编程复杂度 | 高,需处理异步逻辑、回调地狱 | 极高,需处理同步、分布式一致性 |
实际应用 | 浏览器同时渲染多个标签页 聊天服务器处理大量用户消息 | 视频渲染软件利用 GPU 加速 搜索引擎在集群中并行爬取网页 |
Parallelism
- Data Parallelism
- Mapreduce
- Distributed Machine Learning
- Task Parallelism
- Federated Submodel Learning
- Distributed Machine Learning
Amdahl’s Law
公式:
- P: 串行部分的比例
- N: 并行部分的数量
取决于串行部分的比例
Multithreading Models
对比维度 | Kernel Threads(内核线程) | User Threads(用户线程) |
---|---|---|
核心定义 | 由操作系统内核直接管理和调度,内核可见,直接分配CPU时间片和资源,独立执行 | 由用户空间的线程库管理,内核不可见,被视为单个进程内的轻量级任务,依赖内核线程执行 |
管理主体 | 操作系统内核 | 用户空间的线程库(如Pthreads、Java Threads) |
执行依赖 | 独立执行,内核直接调度 | 依赖内核线程执行(需映射到内核线程) |
调度权 | 内核完全控制调度策略(如时间片轮转) | 用户线程库自行调度(如协作式或抢占式) |
上下文切换开销 | 高(需内核态与用户态切换) | 低(仅在用户空间切换) |
多核利用 | 支持真正并行(每个内核线程独立运行) | 受限于内核线程数量(需映射到多核) |
资源占用 | 每个线程占用独立内核栈(通常较大) | 共享进程内核栈,用户栈较小(轻量级) |
阻塞影响 | 单个线程阻塞不影响其他线程 | 若映射到同一内核线程,阻塞会导致所有用户线程暂停 |
适用场景 | 计算密集型任务、实时系统 | I/O密集型任务、高并发场景 |
典型实现 | Windows、Linux、macOS等操作系统原生支持 | Pthreads(POSIX)、Java线程(早期版本)、Go语言的Goroutine(混合模型) |
映射模型 | 一对一(1:1),每个内核线程独立执行 | 多对一(M:1):多个用户线程映射到一个内核线程(如早期Java线程);多对多(M:N):用户线程动态映射到内核线程(如Linux的NPTL、现代Java线程) |
优点 | 支持多核并行、健壮性强、无阻塞风险 | 轻量级、高并发能力、上下文切换快 |
缺点 | 上下文切换开销大、资源占用高 | 多核利用率低、阻塞易导致性能下降 |
通俗比喻 | 如同工厂中的正式员工,由厂长(内核)直接分配任务,每人独立工作,但请假(阻塞)不影响其他人 | 如同工厂中的外包团队,由包工头(线程库)管理,共享一套设备(内核线程),若一人请假(阻塞),整个团队可能暂停 |
实际应用示例 | 科学计算(如矩阵运算)、视频渲染(利用GPU多核) | Web服务器处理大量并发请求(如Node.js的事件循环)、游戏中的多任务处理(如动画与网络通信) |
Lightweight process (LWP): A mapping between user threads and kernel threads
Multithreading models
对比维度 | 多对一(M:1) | 一对一(1:1) | 多对多(M:N) |
---|---|---|---|
映射关系 | 多个用户线程映射到一个内核线程 | 每个用户线程直接映射到一个内核线程 | 用户线程动态映射到多个内核线程 |
内核感知 | 内核不可见,仅用户线程库管理 | 内核直接管理每个线程 | 内核可见,用户线程与内核线程动态关联 |
上下文切换开销 | 低(仅在用户空间切换) | 高(需内核态与用户态切换) | 中等(结合两者特性) |
多核利用率 | 无法利用多核(受限于单个内核线程) | 充分利用多核(每个线程独立运行) | 高效利用多核(动态分配内核线程) |
资源占用 | 低(共享内核栈) | 高(每个线程独立内核栈) | 中等(按需分配内核线程) |
阻塞影响 | 若内核线程阻塞,所有用户线程暂停 | 单个线程阻塞不影响其他线程 | 部分线程阻塞时,其他线程仍可运行 |
适用场景 | I/O密集型任务(如早期Java线程) | 计算密集型任务(如科学计算) | 高并发场景(如Web服务器、Go语言Goroutine) |
典型实现 | 早期Java线程(Solaris绿色线程)、旧版LWP(轻量级进程) | Linux内核线程(clone系统调用)、Windows线程 | GNU的NPTL(Linux原生线程库)、Java 1.2+、Go语言Goroutine |
优点 | 轻量级、上下文切换快 | 支持多核并行、无阻塞风险 | 高效利用多核、高并发能力强 |
缺点 | 无法利用多核,阻塞风险高 | 资源占用高、上下文切换开销大 | 实现复杂度高,需动态调度 |
通俗比喻 | 一个厨师(内核线程)同时处理多个订单(用户线程),但一次只能做一道菜(阻塞时全部暂停) | 每个订单(用户线程)由独立厨师(内核线程)处理,效率高但需雇佣更多厨师(资源消耗大) | 根据订单量(用户线程)动态分配厨师(内核线程),高峰期多派厨师,空闲时减少(平衡资源与效率) |
实际应用场景 | 早期Java Web服务器(轻量级并发) | 视频渲染、科学计算(需多核并行) | 现代Web服务器(如Node.js、Go)、分布式系统(如Kafka) |
Thread Libraries
Tools for manage threads
- POSIX Pthreads
- Java Threads
- Win32 Threads
Pthreads
1 |
|
Implicit Threading
- Thread Pools
- 提前创建多个线程,等待任务到来
- Fork-Join
- 分治法
- OpenMP
- 并行编程接口
- Grand Central Dispatch
- 苹果的并行编程框架
- Intel Threading Building Blocks
- 英特尔的并行编程框架
Threading Issues
关于Kernel和User
学习操作系统到这里,我发现大量出现Kernel和User的概念,这里有一些自己的探索与思考。
溯源
Multics系统(1960年代)
由MIT、贝尔实验室和通用电气联合开发的分时操作系统,首次提出了层次化保护机制(Protection Rings)。系统分为多个特权级别(如Ring 0到Ring 3),其中:- 内核态(Kernel Mode):运行在最高特权级(如Ring 0),可访问所有硬件资源和系统数据。
- 用户态(User Mode):运行在较低特权级(如Ring 3),受限访问敏感资源。
UNIX的继承与简化
贝尔实验室的Ken Thompson和Dennis Ritchie在设计UNIX时,受Multics启发,但简化了保护机制,仅保留两级模式:- 内核态:执行内核代码,直接操作硬件。
- 用户态:运行应用程序,通过系统调用请求内核服务。
为什么需要用户态与内核态分离?
- 安全性:防止用户程序恶意或误操作破坏内核。
- 稳定性:用户程序崩溃不会影响内核运行。
- 资源管理:内核统一调度硬件资源(如CPU、内存)。
思考
内核态与用户态的设计哲学是典型的抓住主要矛盾,忽略次要矛盾。同时体现了严格的hierarchical design。