Python 主进程中如何判断所有子进程结束

在使用多进程编程时,我们经常会遇到需要等待所有子进程结束后才能继续执行的情况。本文将介绍如何在 Python 主进程中判断所有子进程是否结束,并提供一个具体的问题和解决方案。

问题描述

假设我们有一个需要进行大量计算的任务,我们希望通过多进程的方式来加速计算过程。我们将任务分成若干个子任务,每个子任务分配给一个子进程来执行。我们希望在所有子进程都结束后,主进程输出计算结果。

解决方案

Python 提供了多种方式来进行多进程编程,例如使用 multiprocessing 模块,或者使用第三方库 concurrent.futures。这里我们选择使用 multiprocessing 模块来实现。

首先,我们需要创建子进程并将任务分配给它们。可以使用 multiprocessing.Process 类来创建子进程,然后调用 start() 方法来启动子进程。为了能够在主进程中判断子进程是否结束,我们可以将子进程对象保存到一个列表中。

下面是一个示例代码,展示了如何创建子进程并等待它们结束:

import multiprocessing

def worker():
    # 子进程的任务
    print('Worker started')
    # 这里可以是一些耗时的计算任务
    print('Worker finished')

if __name__ == '__main__':
    processes = []

    for _ in range(4):
        p = multiprocessing.Process(target=worker)
        p.start()
        processes.append(p)

    # 等待所有子进程结束
    for p in processes:
        p.join()

    print('All processes finished')

在上面的示例中,我们创建了 4 个子进程,并将它们保存到 processes 列表中。然后,我们使用 join() 方法来等待所有子进程结束。join() 方法会阻塞主进程,直到所有子进程都结束才会继续执行后面的代码。

在实际应用中,我们可能需要更复杂的任务分配和结果收集逻辑。下面是一个更完整的示例,展示了如何将任务分配给子进程并收集它们的计算结果:

import multiprocessing
import random

def worker(task_queue, result_queue):
    # 子进程的任务
    while True:
        task = task_queue.get()
        if task is None:
            break
        result = task * 2  # 这里可以是一些耗时的计算任务
        result_queue.put(result)

if __name__ == '__main__':
    tasks = [random.randint(1, 10) for _ in range(8)]
    task_queue = multiprocessing.Queue()
    result_queue = multiprocessing.Queue()
    processes = []

    # 将任务放入队列
    for task in tasks:
        task_queue.put(task)

    # 创建子进程并分配任务
    for _ in range(4):
        p = multiprocessing.Process(target=worker, args=(task_queue, result_queue))
        p.start()
        processes.append(p)

    # 等待所有子进程结束
    for _ in range(4):
        task_queue.put(None)
    for p in processes:
        p.join()

    # 收集计算结果
    results = []
    while not result_queue.empty():
        result = result_queue.get()
        results.append(result)

    # 输出计算结果
    print('Results:', results)

在上面的示例中,我们使用了两个队列来实现任务分配和结果收集。主进程将任务放入 task_queue 队列,子进程从队列中取出任务并进行计算,然后将结果放入 result_queue 队列。主进程在等待子进程结束后,通过遍历 result_queue 队列来收集计算结果。

甘特图

下面是一个使用甘特图表示的任务执行过程:

gantt
    dateFormat  YYYY-MM-DD
    title 多进程任务执行过程

    section 子进程1
    子进程1任务 :active, 2022-01-01, 2d

    section 子进程2
    子进程2任务 :active, 2022-01-02, 3d

    section 子进程