Python多进程Queue队列及常见问题:Ping Pong示例的改进
在学习Python多进程编程时,使用multiprocessing.Queue
队列可能会遇到一些棘手的问题。例如,经典的Ping-Pong程序中,输出结果常常超出预期。
问题:
许多教程中的Ping-Pong示例代码,使用两个进程分别输出“Ping”和“Pong”,但实际输出数量往往大于预期的次数(例如,预期10次,却输出更多)。
原因分析及解决方案:
问题根源在于对队列q.get()
方法的理解和使用不当。 如果在获取队列元素后没有及时处理或从队列中移除该元素,则多个进程可能会重复读取同一个元素,导致输出结果错误。
下述代码展示了改进后的Ping-Pong程序:
from multiprocessing import Process, Queue
from time import sleep
from os import getpid
def sub_task(name, q):
for i in range(5): # 每个进程循环5次
c = q.get() # 从队列中获取元素
print(f"Process {getpid()}({name}): {c}")
q.task_done() # 通知队列任务已完成
if __name__ == '__main__':
q = Queue()
for i in range(10): # 向队列中放入10个元素
q.put(i)
p1 = Process(target=sub_task, args=('Ping', q))
p2 = Process(target=sub_task, args=('Pong', q))
p1.start()
p2.start()
q.join() # 等待所有任务完成
p1.join()
p2.join()
print("All processes finished.")
此代码通过q.task_done()
方法通知队列任务已完成,并使用q.join()
阻塞主进程,直到所有任务完成,从而避免了多个进程重复读取队列元素的问题,确保了Ping-Pong输出数量准确无误。 这比简单的c = q.get()
后直接使用c
变量更可靠,避免了潜在的竞争条件。
此改进后的版本更清晰地展示了如何正确使用multiprocessing.Queue
,避免了常见的错误,并提供了更健壮的多进程程序。