Python多进程

172 阅读2分钟

Python多进程

Python 提供了 multiprocessing 模块,用于多进程编程。与多线程不同,多进程通过创建独立的内存空间来运行任务,从而绕过了 GIL(全局解释器锁)的限制,非常适合 CPU 密集型任务。

以下是 Python 多进程编程的基本用法和示例:


1. 基本使用

multiprocessing 模块中的 Process 类用于创建子进程。

示例:创建子进程

from multiprocessing import Process
import os
import time
​
def worker(name):
    print(f"Process {name} (PID: {os.getpid()}) is running...")
    time.sleep(2)
    print(f"Process {name} is done.")
​
if __name__ == "__main__":
    print(f"Main process PID: {os.getpid()}")
    
    # 创建并启动子进程
    p1 = Process(target=worker, args=("A",))
    p2 = Process(target=worker, args=("B",))
    
    p1.start()
    p2.start()
    
    # 等待子进程结束
    p1.join()
    p2.join()
    print("All processes are done.")

2. 使用 Pool 创建进程池

multiprocessing.Pool 是一个方便的接口,用于并发执行多个任务。

示例:进程池的 map

from multiprocessing import Pool
import time
​
def task(n):
    time.sleep(1)
    return n * n
​
if __name__ == "__main__":
    with Pool(4) as pool:  # 创建包含 4 个进程的进程池
        results = pool.map(task, range(5))  # 提交任务
        print(results)

示例:进程池的 apply_async

apply_async 提供了异步任务提交方式,并允许通过回调函数处理结果。

from multiprocessing import Pool
import time
​
def task(n):
    time.sleep(1)
    return f"Task {n} done"def callback(result):
    print(result)
​
if __name__ == "__main__":
    with Pool(4) as pool:
        for i in range(5):
            pool.apply_async(task, args=(i,), callback=callback)  # 提交异步任务
        pool.close()  # 禁止提交新任务
        pool.join()   # 等待所有任务完成

3. 数据共享

多进程之间的数据是隔离的,但可以通过 ValueArray 来共享数据,或者使用 Manager 来管理共享资源。

示例:共享变量

from multiprocessing import Process, Value
​
def increment(shared_num):
    for _ in range(1000):
        with shared_num.get_lock():  # 加锁,确保线程安全
            shared_num.value += 1if __name__ == "__main__":
    shared_num = Value('i', 0)  # 共享整数变量,初始值为 0
    
    processes = [Process(target=increment, args=(shared_num,)) for _ in range(4)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()
    
    print(f"Final value: {shared_num.value}")

4. 使用 Manager 管理共享数据

multiprocessing.Manager 提供了字典、列表等可共享的数据结构。

示例:共享列表

from multiprocessing import Process, Manager
​
def worker(shared_list):
    for i in range(5):
        shared_list.append(i)
​
if __name__ == "__main__":
    with Manager() as manager:
        shared_list = manager.list()  # 创建共享列表
        processes = [Process(target=worker, args=(shared_list,)) for _ in range(4)]
        
        for p in processes:
            p.start()
        for p in processes:
            p.join()
        
        print(f"Shared list: {shared_list}")

5. 捕获异常

可以通过 tryexcept 捕获子进程中的异常。

示例:捕获异常

from multiprocessing import Process
​
def worker(n):
    if n == 2:
        raise ValueError("Something went wrong!")
    print(f"Process {n} done.")
​
if __name__ == "__main__":
    processes = [Process(target=worker, args=(i,)) for i in range(5)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()

6. 注意事项

  1. 使用 if __name__ == "__main__" 在 Windows 系统上,必须将多进程代码放在 if __name__ == "__main__" 中,否则会引发无限递归。
  2. 避免全局变量的使用 各个进程拥有独立的内存空间,修改全局变量不会影响其他进程。
  3. 多进程适合 CPU 密集型任务 对于 I/O 密集型任务,可以优先考虑多线程。