在现代计算机系统中,多进程编程是提升程序性能的核心技术之一。无论是高并发的服务器应用,还是复杂的数据处理任务,合理利用多进程都能显著提高资源利用率。然而,进程间的资源竞争、通信复杂度等问题也让开发者望而生畏。本文将从基础概念出发,结合Python的multiprocessing
模块,通过代码实战和案例分析,系统讲解多进程编程的核心要点,助你轻松攻克并发编程难题!
引言
1. 进程基础知识
1.1 进程概述
1.2 进程的五大特征
1.3 进程调度算法
1.4 并行与并发的核心区别
1.5 进程状态转换图解析
2. Python多进程编程实战
2.1 使用multiprocessing.Process类
关键参数说明:
2.2 自定义进程类(继承Process)
2.3 进程的常用方法与属性
核心方法:
关键属性:
3. 资源竞争问题与锁机制
3.1 银行转账问题:共享变量的同步控制
3.2 火车售票问题:全局锁解决超卖与负数票
3.3 锁机制的原理与使用场景
4. 高级技巧与优化建议
4.1 进程间通信(IPC)的三种方式
4.2 守护进程与资源回收
4.3 多进程调试技巧
5. 总结与扩展学习
6. 参考资料与推荐阅读
定义:进程是程序的一次动态执行实例,拥有独立的内存空间和系统资源。
关键点:
进程是操作系统资源分配的基本单位。
多进程的隔离性强,一个进程崩溃不会影响其他进程。
适用于CPU密集型任务(如科学计算、图像处理)。
特征 | 描述 |
---|---|
动态性 | 进程由创建到终止是动态的生命周期。 |
并发性 | 多个进程可同时存在于内存中,交替执行。 |
独立性 | 进程是资源分配和调度的独立单位。 |
异步性 | 进程执行速度不可预知,需通过同步机制协调。 |
结构特征 | 进程由程序、数据、进程控制块(PCB)三部分组成。 |
先来先服务(FCFS):按进程到达顺序分配CPU。
短作业优先(SJF):优先执行预计运行时间短的进程。
时间片轮转(RR):每个进程分配固定时间片,循环执行。
多级反馈队列:结合优先级和时间片的混合调度策略。
并行:多核CPU同时执行多个进程(微观层面)。
并发:单核CPU通过时间片切换模拟“同时”执行(宏观层面)。
示例:
并行:四核CPU同时处理四个独立任务。
并发:单核CPU交替处理网页请求和文件下载。
就绪→运行:被调度器选中,获得CPU。
运行→阻塞:等待I/O操作或资源。
阻塞→就绪:等待事件完成,重新参与调度。
multiprocessing.Process
类from multiprocessing import Process
import os
def task(num):
print(f"子进程PID: {os.getpid()}, 参数: {num}")
if __name__ == '__main__':
p = Process(target=task, args=(1,)) # 创建进程对象
p.start() # 启动进程
p.join() # 等待子进程结束
print("父进程结束")
target
:子进程执行的函数。
args
:以元组形式传递的参数。
Process
)class MyProcess(Process):
def __init__(self, name):
super().__init__(name=name) # 显式传递进程名称
def run(self):
print(f"{self.name}进程PID: {os.getpid()}")
if __name__ == '__main__':
p = MyProcess("自定义进程")
p.start()
注意:必须重写run()
方法,否则默认执行空操作。
start()
:启动进程。
join(timeout)
:阻塞父进程,等待子进程结束。
terminate()
:强制终止进程(慎用,可能导致僵尸进程)。
daemon
:设为True
时,子进程随父进程终止。
pid
:进程的唯一标识符。
问题场景:多个进程同时修改共享变量(如账户余额),导致数据不一致。
解决方案:使用Lock
锁确保原子操作。
from multiprocessing import Process, Value, Lock
def transfer(money, lock):
lock.acquire()
money.value += 10 # 存钱操作
lock.release()
if __name__ == '__main__':
money = Value('i', 100) # 初始余额100
lock = Lock()
p1 = Process(target=transfer, args=(money, lock))
p2 = Process(target=transfer, args=(money, lock))
p1.start(); p2.start()
p1.join(); p2.join()
print("最终余额:", money.value) # 输出120
问题场景:多个售票窗口同时卖票,导致票数错误。
解决方案:全局锁控制共享资源访问。
from multiprocessing import Process, Value, Lock
class TicketSeller(Process):
def __init__(self, tickets, name, lock):
super().__init__()
self.tickets = tickets # 共享票数
self.name = name # 窗口名称
self.lock = lock # 全局锁
def run(self):
while True:
self.lock.acquire()
if self.tickets.value > 0:
print(f"{self.name}卖出第{self.tickets.value}张票")
self.tickets.value -= 1
self.lock.release()
else:
self.lock.release()
break
if __name__ == '__main__':
tickets = Value('i', 20) # 初始20张票
lock = Lock()
p1 = TicketSeller(tickets, "窗口1", lock)
p2 = TicketSeller(tickets, "窗口2", lock)
p1.start(); p2.start()
原理:通过锁的acquire()
和release()
方法,确保同一时间只有一个进程访问共享资源。
适用场景:
文件读写操作。
数据库事务处理。
共享内存变量的修改。
管道(Pipe):单向或双向通信,适用于父子进程。
队列(Queue):线程安全的先进先出数据结构。
共享内存(Value/Array):高效但需手动同步。
守护进程:通过p.daemon = True
设置,随主进程终止。
资源回收:使用join()
确保子进程正常退出,避免僵尸进程。
日志记录:每个进程独立记录日志文件。
断点调试:使用IDE(如PyCharm)附加到子进程。
多进程优势:高隔离性、多核利用率高。
挑战:进程间通信复杂、资源竞争需精细控制。
扩展方向:
学习multiprocessing.Pool
实现进程池。
探索分布式进程(如Celery
框架)。
Python官方文档 - multiprocessing
《Python并行编程手册》 - 机械工业出版社
CSDN专栏:Python并发编程实战