下篇:Python 多任务编程入门(二)—— 进程同步、进程池与注意事项
目录
一、进程间的资源竞争与锁
1. 进程锁(Lock)的作用
2. 使用步骤
3. 代码示例
二、进程池:高效管理大量子进程
1.进程池的原理
2. 核心方法
3. 示例:用进程池批量计算平方
三、多进程编程的重要注意事项
1. 全局变量不共享
2. 主进程与子进程的结束顺序
四、总结:什么时候该用进程?
一、进程间的资源竞争与锁
虽然进程之间默认不共享内存,但当它们同时访问同一个外部资源(如同一个文件、同一台打印机、同一个网络端口)时,仍然会产生冲突。例如,两个进程同时向同一个文件写入数据,可能会造成数据错乱。
1. 进程锁(Lock)的作用
锁就像一个门上的锁:谁拿到钥匙,谁就进去使用资源,其他人只能在门外等待。这样就能保证同一时间只有一个进程操作共享资源。
2. 使用步骤
创建锁:
lock = multiprocessing.Lock()在子进程中获取锁:
lock.acquire()(如果锁已被占用,当前进程会阻塞)释放锁:
lock.release()(通常放在finally中,确保一定释放)
3. 代码示例
import multiprocessing import time def task(lock, name): lock.acquire() try: print(f"{name} 获得锁,开始工作") time.sleep(1) print(f"{name} 工作完成") finally: lock.release() if __name__ == '__main__': lock = multiprocessing.Lock() p1 = multiprocessing.Process(target=task, args=(lock, '进程1')) p2 = multiprocessing.Process(target=task, args=(lock, '进程2')) p1.start() p2.start() # 进程1 获得锁,开始工作 # 进程1 工作完成 # 进程2 获得锁,开始工作 # 进程2 工作完成运行结果会看到两个进程不会同时打印“开始工作”,而是先后执行。
注意:同一个进程内,不能连续两次调用acquire()而不释放,否则会导致死锁(程序卡住)。
二、进程池:高效管理大量子进程
假如你要执行 100 个短小的任务,每个任务只耗时 0.1 秒。如果为每个任务创建一个进程,创建和销毁进程的开销可能远大于任务本身。这时,进程池(Pool)是更优方案。
1.进程池的原理
进程池预先创建一批固定数量的子进程(比如 4 个),然后把任务丢给它们。一个任务完成后,该进程并不销毁,而是去执行下一个任务。这样可以避免频繁创建/销毁进程的代价。
2. 核心方法
Pool(processes=n):创建进程池,最多同时运行 n 个进程。apply_async(func, args, kwargs):异步提交任务(推荐),主进程不等待。map(func, iterable):批量提交,类似内置map,会阻塞直到全部完成。close():关闭进程池,不再接受新任务。join():等待池中所有任务执行完毕。
3. 示例:用进程池批量计算平方
import multiprocessing import os def square(x): print(f"进程 {os.getpid()} 计算 {x} 的平方 = {x*x}") return x*x if __name__ == '__main__': with multiprocessing.Pool(processes=4) as pool: results = pool.map(square, range(10)) print("所有结果:", results)with语句会自动调用close()和join(),非常方便。
三、多进程编程的重要注意事项
1. 全局变量不共享
每个进程有独立的内存空间,子进程会拷贝主进程的全局变量,但修改子进程中的变量不会影响主进程,反之亦然。如果需要进程间通信,请使用Queue、Pipe或共享内存。
2. 主进程与子进程的结束顺序
默认情况下,主进程会等待所有子进程结束后才退出。如果你希望主进程退出时立即终止所有子进程,有两种方法:
守护进程:设置
p.daemon = True,主进程结束时会自动杀死守护子进程。
p = multiprocessing.Process(target=func) p.daemon = True p.start()- 手动终止:调用
p.terminate()强制结束子进程。
p.terminate() # 立即终止子进程四、总结:什么时候该用进程?
CPU 密集型任务(如图像处理、大量数学计算):进程能利用多核 CPU,效果显著。
任务相互独立,不需要频繁通信:进程天然隔离,安全可靠。
大量短任务:配合进程池,避免频繁创建销毁的开销。
如果任务主要是 I/O 密集型(如网络请求、文件读写),线程或协程可能更轻量。但无论如何,掌握进程编程是 Python 多任务进阶的必经之路。
下篇核心回顾:
进程锁(
Lock)解决资源竞争。进程池(
Pool)高效管理大量子进程。全局变量不共享,主进程与子进程的结束方式需留意。
