Python 多进程编程:multiprocessing 模块全面解析
在 Python 编程里,当面临 CPU 密集型任务时,由于全局解释器锁(GIL)的存在,多线程往往无法充分发挥多核 CPU 的性能优势。而 multiprocessing
模块为我们提供了多进程编程的解决方案,它允许程序在多个进程中并行执行任务,从而有效利用多核 CPU 的计算能力。本文将围绕 multiprocessing
模块展开,详细介绍进程的创建、管理、进程间通信、同步机制等内容,帮助读者掌握 Python 中的多进程编程技巧。
文章目录
一、multiprocessing 模块概述
multiprocessing
模块是 Python 标准库的一部分,提供了创建和管理进程的高级接口。与多线程不同,每个进程都有自己独立的 Python 解释器和内存空间,因此不受 GIL 的限制,可以真正实现并行计算。该模块支持跨平台使用,在 Windows、Linux 和 macOS 等操作系统上都能正常工作。
二、进程的创建与启动
(一)使用 Process
类创建进程
Process
类是 multiprocessing
模块中用于创建进程的核心类。创建进程有两种常见的方式:
- 传入可调用对象
import multiprocessing
def print_numbers():
for i in range(5):
print(i)
# 创建进程对象
process = multiprocessing.Process(target=print_numbers)
# 启动进程
process.start()
# 等待进程结束
process.join()
- 继承
Process
类
import multiprocessing
class PrintNumbersProcess(multiprocessing.Process):
def run(self):
for i in range(5):
print(i)
# 创建进程对象
process = PrintNumbersProcess()
# 启动进程
process.start()
# 等待进程结束
process.join()
(二)进程的常用属性和方法
属性 / 方法 | 描述 |
---|---|
name | 进程的名称,可在创建进程时通过 name 参数指定,默认为 Process-N 形式 |
pid | 进程的标识符,是一个整数,进程启动后才会有值 |
is_alive() | 判断进程是否处于活动状态 |
start() | 启动进程,调用进程的 run() 方法 |
join([timeout]) | 等待进程结束,timeout 为可选的超时时间 |
terminate() | 终止进程,会发送 SIGTERM 信号给进程 |
kill() | 强制终止进程,会发送 SIGKILL 信号给进程(仅在 Unix 系统上可用) |
三、进程间通信(IPC)
由于每个进程都有自己独立的内存空间,进程间需要通过特定的机制进行通信。multiprocessing
模块提供了多种进程间通信的方式。
(一)队列(Queue
)
Queue
是一种线程和进程安全的队列,可用于在多个进程之间传递数据。
import multiprocessing
def producer(queue):
for i in range(5):
queue.put(i)
def consumer(queue):
while True:
item = queue.get()
if item is None:
break
print(item)
# 创建队列对象
queue = multiprocessing.Queue()
# 创建生产者和消费者进程
producer_process = multiprocessing.Process(target=producer, args=(queue,))
consumer_process = multiprocessing.Process(target=consumer, args=(queue,))
# 启动进程
producer_process.start()
consumer_process.start()
# 等待生产者进程结束
producer_process.join()
# 向队列中放入结束标志
queue.put(None)
# 等待消费者进程结束
consumer_process.join()
(二)管道(Pipe
)
Pipe
用于在两个进程之间建立双向通信。它返回一对连接对象,分别代表管道的两端。
import multiprocessing
def sender(conn):
message = "Hello from sender!"
conn.send(message)
conn.close()
def receiver(conn):
message = conn.recv()
print(f"Received: {message}")
conn.close()
# 创建管道
parent_conn, child_conn = multiprocessing.Pipe()
# 创建发送者和接收者进程
sender_process = multiprocessing.Process(target=sender, args=(child_conn,))
receiver_process = multiprocessing.Process(target=receiver, args=(parent_conn,))
# 启动进程
sender_process.start()
receiver_process.start()
# 等待进程结束
sender_process.join()
receiver_process.join()
(三)共享内存
multiprocessing
模块提供了 Value
和 Array
用于在多个进程之间共享内存。
import multiprocessing
def increment(counter):
for _ in range(1000):
with counter.get_lock():
counter.value += 1
# 创建共享变量
counter = multiprocessing.Value('i', 0)
# 创建多个进程
processes = [multiprocessing.Process(target=increment, args=(counter,)) for _ in range(5)]
# 启动进程
for process in processes:
process.start()
# 等待进程结束
for process in processes:
process.join()
print(f"Final counter value: {counter.value}")
四、进程同步机制
与多线程编程类似,多进程编程中也需要同步机制来保护共享资源,避免数据竞争和不一致问题。
(一)锁(Lock
)
Lock
用于确保同一时间只有一个进程可以访问共享资源。
import multiprocessing
def worker(lock, shared_variable):
lock.acquire()
try:
shared_variable.value += 1
finally:
lock.release()
# 创建锁对象和共享变量
lock = multiprocessing.Lock()
shared_variable = multiprocessing.Value('i', 0)
# 创建多个进程
processes = [multiprocessing.Process(target=worker, args=(lock, shared_variable)) for _ in range(5)]
# 启动进程
for process in processes:
process.start()
# 等待进程结束
for process in processes:
process.join()
print(f"Final shared variable value: {shared_variable.value}")
(二)信号量(Semaphore
)
Semaphore
用于控制同时访问某个资源的进程数量。
import multiprocessing
import time
# 创建信号量对象,允许 2 个进程同时访问
semaphore = multiprocessing.Semaphore(2)
def worker():
semaphore.acquire()
try:
print("Working...")
time.sleep(2)
finally:
semaphore.release()
# 创建多个进程
processes = [multiprocessing.Process(target=worker) for _ in range(5)]
# 启动进程
for process in processes:
process.start()
# 等待进程结束
for process in processes:
process.join()
(三)事件(Event
)
Event
用于进程间的通信和同步,一个进程可以设置事件,其他进程可以等待事件被设置。
import multiprocessing
import time
# 创建事件对象
event = multiprocessing.Event()
def waiter():
print("Waiting for event...")
# 等待事件被设置
event.wait()
print("Event is set!")
# 创建等待进程
waiter_process = multiprocessing.Process(target=waiter)
waiter_process.start()
# 主线程休眠 3 秒后设置事件
time.sleep(3)
event.set()
# 等待等待进程结束
waiter_process.join()
五、进程池
multiprocessing.Pool
类用于创建进程池,它可以管理多个工作进程,提高进程的复用性和效率。
import multiprocessing
def task(n):
return n * 2
# 创建进程池
with multiprocessing.Pool(processes=3) as pool:
# 提交任务
results = pool.map(task, [1, 2, 3, 4, 5])
print(results)
六、多进程编程的注意事项
- 资源管理:每个进程都有自己独立的资源,如内存、文件句柄等。在使用多进程时,要注意合理管理资源,避免资源泄漏。
- 序列化问题:在进行进程间通信时,传递的数据需要能够被序列化。Python 中的
pickle
模块用于序列化和反序列化对象,但不是所有的对象都可以被pickle
处理。 - 跨平台兼容性:虽然
multiprocessing
模块支持跨平台使用,但不同操作系统在进程创建和管理方面可能存在一些差异,在编写跨平台代码时需要注意。
总结
multiprocessing
模块为 Python 开发者提供了强大的多进程编程能力。通过创建和管理进程、使用进程间通信机制和同步机制以及利用进程池,我们可以实现并行执行任务,充分发挥多核 CPU 的计算能力。然而,在使用多进程编程时,需要注意资源管理、序列化问题和跨平台兼容性等问题,以确保程序的正确性和稳定性。
TAG: Python、multiprocessing 模块、多进程编程、进程间通信、进程同步、进程池
相关学习资源
- Python 官方文档(https://docs.python.org/zh-cn/3.12/library/multiprocessing.html):提供了
multiprocessing
模块的详细文档,包括所有类、方法和属性的介绍,是学习该模块的权威资料。 - Tekin的Python编程秘籍库: Python 实用知识与技巧分享,涵盖基础、爬虫、数据分析等干货 本 Python 专栏聚焦实用知识,深入剖析基础语法、数据结构。分享爬虫、数据分析等热门领域实战技巧,辅以代码示例。无论新手入门还是进阶提升,都能在此收获满满干货,快速掌握 Python 编程精髓。