- 进程(Process):系统资源分配的基本单位,拥有独立的地址空间、文件描述符、进程 ID 等资源
- 线程(Thread):CPU 调度的基本单位,同一进程内的线程共享地址空间和资源
- 轻量级进程(LWP):Linux 通过
clone()系统调用实现线程,本质是共享资源的进程
创建 → 就绪(R) ⇄ 运行(R) → 终止(Z)
↓ ↑
阻塞/睡眠(S/D)
状态说明:
- R (Running/Runnable):运行或就绪状态
- S (Interruptible Sleep):可中断睡眠,等待资源或事件
- D (Uninterruptible Sleep):不可中断睡眠,通常等待 IO
- Z (Zombie):僵尸状态,进程已终止但父进程未回收
- T (Stopped):暂停状态
Linux 采用 CFS(完全公平调度器,Completely Fair Scheduler):
- 基于虚拟运行时间(vruntime)调度
- 红黑树维护就绪队列
- 时间片动态分配,保证每个进程的公平性
- 支持优先级(nice 值:-20 到 19,数值越小优先级越高)
# 查看进程信息
ps aux # 查看所有进程
ps -eLf # 查看所有线程
top # 实时监控进程
htop # 增强版 top
# 进程控制
kill -SIGTERM <pid> # 优雅终止进程(15信号)
kill -SIGKILL <pid> # 强制杀死进程(9信号)
nice -n 10 ./app # 以指定优先级启动
renice -n 5 -p <pid> # 调整运行中进程优先级
# 进程追踪
strace -p <pid> # 追踪系统调用
pstack <pid> # 查看进程调用栈
lsof -p <pid> # 查看进程打开的文件
# CPU 亲和性
taskset -c 0,1 ./app # 将进程绑定到指定 CPU 核心完整代码见:examples/python/process-pool/
import multiprocessing as mp
import time
from typing import Callable
class ProcessPool:
"""简单的进程池实现"""
def __init__(self, num_workers: int = 4):
self.num_workers = num_workers
self.task_queue = mp.Queue()
self.result_queue = mp.Queue()
self.workers = []
def worker(self):
"""工作进程主循环"""
while True:
task = self.task_queue.get()
if task is None: # 毒丸,退出信号
break
func, args = task
try:
result = func(*args)
self.result_queue.put(('success', result))
except Exception as e:
self.result_queue.put(('error', str(e)))
def start(self):
"""启动工作进程"""
for _ in range(self.num_workers):
p = mp.Process(target=self.worker)
p.start()
self.workers.append(p)
def submit(self, func: Callable, *args):
"""提交任务"""
self.task_queue.put((func, args))
def shutdown(self):
"""关闭进程池"""
for _ in range(self.num_workers):
self.task_queue.put(None) # 发送退出信号
for p in self.workers:
p.join()
# 使用示例
def cpu_intensive_task(n):
"""CPU 密集型任务示例"""
return sum(i * i for i in range(n))
if __name__ == '__main__':
pool = ProcessPool(num_workers=4)
pool.start()
# 提交任务
for i in range(10):
pool.submit(cpu_intensive_task, 1000000)
# 获取结果
for _ in range(10):
status, result = pool.result_queue.get()
print(f"Task result: {status}, {result}")
pool.shutdown()原因:子进程退出后,父进程未调用 wait()/waitpid() 回收
危害:占用进程表项,系统进程数达到上限
解决方案:
import signal
# 设置 SIGCHLD 信号处理器自动回收
signal.signal(signal.SIGCHLD, signal.SIG_IGN)- 减少不必要的系统调用
- 使用 CPU 亲和性绑定核心
- 合理设置进程优先级
- 避免频繁的阻塞操作
- 父进程先于子进程退出,子进程被 init 进程(PID 1)接管
- 通常不会造成问题,init 会自动回收
进程管理是操作系统的核心功能,理解进程状态转换、调度算法对于编写高性能后台服务至关重要。
关键要点:
- ✅ 进程 vs 线程:资源分配 vs CPU调度
- ✅ CFS调度器:公平性保证
- ✅ 避免僵尸进程:正确处理SIGCHLD信号
- ✅ 进程池模式:复用进程,减少创建开销
- Linux进程调度详解
- 《深入理解Linux内核》第3章:进程
- CFS调度器源码分析
💡 思考题:
- 进程和线程的本质区别是什么?什么时候用进程,什么时候用线程?
- 如何排查和清理僵尸进程?
- CPU密集型任务应该用多进程还是多线程?为什么?
⏭️ 下一节:内存管理