pin_drop当前位置:知识文库 ❯ 图文
multiprocessing模块详解 - Python多进程编程指南
概述
multiprocessing 是Python标准库中用于创建和管理多进程的模块。与多线程不同,多进程通过启动独立的操作系统进程来实现真正的并行计算,有效绕过了Python的GIL(全局解释器锁)限制。
每个进程拥有独立的内存空间、Python解释器和执行状态,因此多进程非常适合CPU密集型任务,如数值计算、数据处理、图像处理等。multiprocessing模块提供了与threading模块相似的API,降低了学习成本。
语法
代码示例
from multiprocessing import Process, current_process, cpu_count
# Process 构造函数
process = Process(target=函数名, args=(参数1, 参数2, ...), name='进程名', daemon=False)
# 参数说明:
# target: 进程要执行的函数(不加括号)
# args: 传递给 target 的位置参数元组
# name: 进程名称,便于调试
# daemon: 是否为守护进程(True表示父进程退出时子进程自动终止)
# 常用属性和方法:
# process.start() — 启动进程
# process.join(timeout=None) — 等待进程结束
# process.terminate() — 强制终止进程
# process.is_alive() — 检查进程是否存活
# process.pid — 获取进程ID
# current_process().name — 获取当前进程名
# cpu_count() — 获取CPU核心数基本用法
创建和启动进程
代码示例
from multiprocessing import Process
import time
def worker(name, delay):
"""工作进程函数"""
print(f"进程 {name} 启动")
time.sleep(delay)
print(f"进程 {name} 完成")
if __name__ == '__main__':
# 创建进程对象
p1 = Process(target=worker, args=('A', 2), name='Worker-A')
p2 = Process(target=worker, args=('B', 1), name='Worker-B')
# 启动进程
p1.start()
p2.start()
# 等待进程结束
p1.join()
p2.join()
print("所有子进程已结束")批量创建进程
代码示例
from multiprocessing import Process
import time
def compute_task(task_id):
print(f"任务 {task_id} 开始执行")
time.sleep(1)
print(f"任务 {task_id} 完成")
if __name__ == '__main__':
processes = []
# 批量创建并启动
for i in range(5):
p = Process(target=compute_task, args=(i,))
processes.append(p)
p.start()
# 统一等待所有进程结束
for p in processes:
p.join()
print("所有任务执行完毕")代码示例
示例1:CPU密集型任务并行计算
代码示例
from multiprocessing import Process, cpu_count
import time
import math
def calculate_primes(n):
"""计算前n个素数(CPU密集型)"""
primes = []
num = 2
while len(primes) < n:
is_prime = True
for i in range(2, int(math.sqrt(num)) + 1):
if num % i == 0:
is_prime = False
break
if is_prime:
primes.append(num)
num += 1
print(f"找到 {len(primes)} 个素数")
if __name__ == '__main__':
start = time.time()
# 使用多进程并行计算
processes = []
num_cores = cpu_count()
print(f"CPU核心数: {num_cores}")
for i in range(num_cores):
p = Process(target=calculate_primes, args=(50000,))
processes.append(p)
p.start()
for p in processes:
p.join()
print(f"多进程耗时: {time.time() - start:.2f} 秒")示例2:进程间数据隔离
代码示例
from multiprocessing import Process
# 全局变量
counter = 0
def increment():
global counter
for _ in range(100000):
counter += 1
print(f"子进程 counter = {counter}")
if __name__ == '__main__':
p1 = Process(target=increment)
p2 = Process(target=increment)
p1.start()
p2.start()
p1.join()
p2.join()
print(f"主进程 counter = {counter}")
# 输出:主进程 counter = 0
# 因为每个进程都有自己的 counter 副本,互不影响注意事项
注意1:Windows系统必须使用
if __name__ == '__main__':包裹进程创建代码,否则会导致无限递归创建子进程的错误。
注意2:进程数不应超过CPU核心数。过多的进程会导致CPU上下文切换开销增加,反而降低性能。建议使用
multiprocessing.cpu_count()获取核心数作为参考。
小结
-
multiprocessing:Python标准库多进程模块,实现真正的并行计算
-
Process.start()/join():start启动进程,join等待进程结束
-
进程间隔离:每个进程拥有独立内存,全局变量不共享
-
适用场景:CPU密集型任务,不受GIL限制
练习题
练习1
编写程序,使用multiprocessing模块创建4个子进程,每个子进程计算一个数字列表的和,验证进程间数据隔离的特性。
练习2
编写一个函数,使用多进程并行计算1到10000000的累加和,与单线程版本对比执行时间,分析性能差异。
常见问题
为什么Windows上必须使用if __name__ == '__main__'?
Windows不支持fork系统调用,multiprocessing使用spawn方式创建子进程:通过重新导入主模块来初始化子进程。如果没有__main__保护,子进程导入主模块时会再次执行创建进程的代码,导致无限递归。
多进程和多线程应该如何选择?
CPU密集型任务(数学计算、图像处理、数据分析)选择多进程,可以绕过GIL实现真正并行。I/O密集型任务(网络请求、文件读写、数据库查询)选择多线程,线程创建开销小且GIL在I/O操作时会释放。
进程之间如何共享数据?
进程之间内存隔离,但有多种方式可以通信:Queue(进程安全队列)、Pipe(双向管道)、Value/Array(共享内存)、Manager(共享字典/列表等)。其中Queue和Pipe是最常用的方式。
本文涉及AI创作
内容由AI创作,请仔细甄别