Python多进程并行multiprocess基础

Python多进程并行multiprocess基础

  • [一、 简介](#一、 简介)
  • [二、 核心组件](#二、 核心组件)
    • [1、 Process类](#1、 Process类)
    • [2、 Pool](#2、 Pool)
      • [`Pool.map(func, iterable)`](#Pool.map(func, iterable))
      • [`Pool.starmap(func, iterable_of_args)`](#Pool.starmap(func, iterable_of_args))
      • [`Pool.apply(func, args=())`](#Pool.apply(func, args=()))
      • [`Pool.apply_async(func, args=(), callback=None)`](#Pool.apply_async(func, args=(), callback=None))
      • [`Pool.map_async(func, iterable, callback=None)`](#Pool.map_async(func, iterable, callback=None))
    • [3、 进程间通信的部分待补充](#3、 进程间通信的部分待补充)
  • 三、阻塞和异步的概念

一、 简介

python中多进程编程可以通过内联的模块multiprocess实现。multiprocess模块是用于并行处理任务的工具,通过创建多个独立的进程(process)可以避开Cpython的全局解释器锁(GIL),适合于CPU密集型任务。

全局解释器锁(GIL, Global Interpreter Lock)是 CPython(Python 最常用的解释器实现)中的一个互斥锁,它的作用是:在同一时间只允许一个线程执行 Python 字节码(Python 原生代码)

GIL使得在多线程不用担心python对象的内存管理问题,Python 内置的内存分配、引用计数、垃圾回收等操作都只会由一个线程操作,不会"同时"被多个线程修改。内存管理的过程是串行的、安全的,单GIL保护的是python对象的内存操作,并不保证业务逻辑线程安全。

项目 是否线程安全 GIL 是否保护
Python 对象的引用计数
Python 内置内存分配器
变量、自增 赋值逻辑
多线程逻辑操作同一 dict/list

二、 核心组件

1、 Process类

multiprocessing.Process 是multiprocessing 模块中用于创建并管理子进程的类。

基本用法如下

python 复制代码
from multiprocessing import Process

def worker(num):
	print(f"Worker {num} is running")
if __name__ == "__main__":
	p = Process(target=worker, arg(1, )) # 创建一个进程,目标函数worker,传入参数1
	p.start()	# 启动进程,进程开始运行worker函数
	p.join()	# 主进程等待子进程结束

创建Process对象

Process的构造参数

参数名 类型 说明 默认值
group None 保留参数,目前未使用,必须是None None
target callable 进程启动后调用的目标函数 None
name str 进程的名字,可以用来区分不同的进程,主要用于调试和日志 Process-N自动命名
args tuple 传给target函数的位置参数,元组形式 ()(空元组)
kwargs dict 传给target函数的关键字参数,以字典形式 {}(空字典)
daemon bool 是否将进程设置为守护进程(后台进程),守护进程会随着主进程退出自动结束 继承父进程值

创建多个进程

python 复制代码
from multiprocessing import Process

def worker(num):
    print(f"Worker {num} started")
    # 模拟工作
    import time
    if num == 2:
        time.sleep(4)
    else:
        time.sleep(2)
    print(f"Worker {num} finished")

if __name__ == "__main__":
    processes = []
    for i in range(4):
        p = Process(target=worker, args=(i,))
        p.start()
        processes.append(p)
    
    for p in processes:
        p.join()  # 等待所有子进程结束
    print("All workers finished")

输出结果:

python 复制代码
Worker 0 started
Worker 1 started
Worker 2 started
Worker 3 started
Worker 0 finished
Worker 1 finished
Worker 3 finished
Worker 2 finished
All workers finished

使用Process创建的子进程和父进程之间相互独立,子进程有自己的内存空间,父子进程之间不共享内存,需要通过进程间通信协议(IPC)机制如Queue、Pipe、Manager来传递数据。

涉及进程间通信部分的内容暂时还没有遇到,遇到了再补充吧


2、 Pool

Pool是multiprocess中的进程池对象,用于管理一组进程的工作,自动维护一定数量的进程,避免频繁创建和销毁进程带来的开销。

参数名 类型 作用
processes int 指定进程数
initializer callable 每个子进程启动时运行一次
initargs tuple initializer 的参数
maxtasksperchild int 限制每个进程最多执行的任务数
context 特殊对象 控制启动方式(spawn 等)

常用参数是进程数

Pool常用方法如下

Pool.map(func, iterable)

类似于map函数,并行执行func,但是func函数只能接收一个参数,其返回值为一个有序结果列表。

python 复制代码
from multiprocessing import Pool

def square(x):
    return x * x

if __name__ == "__main__":
    with Pool(4) as pool:
        results = pool.map(square, [1, 2, 3, 4, 5])
        print(results)  # [1, 4, 9, 16, 25]

Pool.starmap(func, iterable_of_args)

和map基本一样,但是func可以接收多个参数,参数以list[tuple]的形式传入。

python 复制代码
from multiprocessing import Pool

def power(base, exp):
    return base ** exp

if __name__ == "__main__":
    with Pool(3) as pool:
        results = pool.starmap(power, [(2, 3), (3, 2), (4, 1)])
        print(results)  # [8, 9, 4]

Pool.apply(func, args=())

一次调用只会使用一个进程,需要多次调用,不是真正的并行,同时会阻塞

python 复制代码
from multiprocessing import Pool

def add(x, y):
    return x + y

if __name__ == "__main__":
    with Pool(2) as pool:
        result = pool.apply(add, (3, 5))
        print(result)  # 8

Pool.apply_async(func, args=(), callback=None)

和apply不同的是apply_async是异步非阻塞的,**"异步非阻塞"**是指:任务会被并行执行,主线程不需要等待任务完成就可以继续往下运行。可以在稍后用 .get() 来获取结果,也可以设置回调函数 callback= 自动处理结果。

python 复制代码
from multiprocessing import Pool
import time

def slow_function(x):
    time.sleep(2)
    return x * 2

if __name__ == '__main__':
    with Pool(2) as pool:
        # 异步提交任务
        result1 = pool.apply_async(slow_function, args=(10,))
        result2 = pool.apply_async(slow_function, args=(20,))

        # 主进程继续执行,不会等待
        print("Tasks submitted... doing other things meanwhile...")

        # 等待并获取结果
        print("Result 1:", result1.get())
        print("Result 2:", result2.get())

程序会在 ~2 秒后输出两个结果,而不是 ~4 秒。

Pool.map_async(func, iterable, callback=None)

是map的异步非阻塞版。

python 复制代码
from multiprocessing import Pool

def square(x):
    return x * x

with Pool(4) as pool:
    result = pool.map_async(square, [1, 2, 3, 4])
    print("Tasks submitted.")
    
    # 等待最多5秒后拿结果
    print("Results:", result.get(timeout=5))  # [1, 4, 9, 16]

3、 进程间通信的部分待补充

未完待续...


三、阻塞和异步的概念

阻塞和异步是两个经常一起出现的词

首先明确一些阻塞和异步的概念

异步:是指任务调度的方式,调用任务者发起一个任务后,不等待任务完成,接着执行后面的代码,任务在将来某个时间点完成,结果通过回调函数、事件通知、等待对象获得。

非阻塞:是发起一项操作,不用等待操作完成就能继续做别的事,常见于IO,更侧重于操作

几种方法的对比

方法 是否阻塞 是否可多参数 返回值类型 回调支持
map() ✅ 是 ❌ 否 结果列表 ❌ 无
starmap() ✅ 是 ✅ 是 结果列表 ❌ 无
apply() ✅ 是 ✅ 是 单个结果 ❌ 无
apply_async() ❌ 否 ✅ 是 AsyncResult ✅ 支持
map_async() ❌ 否 ❌ 否 AsyncResult ✅ 支持
相关推荐
高级测试工程师欧阳4 分钟前
python中selenium怎么使用
python·pandas
B612 little star king7 分钟前
UNIKGQA论文笔记
论文阅读·人工智能·笔记·自然语言处理·知识图谱
BertieHuang17 分钟前
(一)深入源码,从 0 到 1 实现 Cursor
人工智能·python·程序员
He19550123 分钟前
Go初级二
开发语言·后端·golang
reddish25 分钟前
用大模型“语音指挥”网站运维?MCP + Coze 实现无代码自动化管理实战
人工智能·程序员·架构
♡喜欢做梦27 分钟前
企业级大模型解决方案:架构、落地与代码实现
人工智能·ai·架构
Coovally AI模型快速验证27 分钟前
全景式综述|多模态目标跟踪全面解析:方法、数据、挑战与未来
人工智能·深度学习·算法·机器学习·计算机视觉·目标跟踪·无人机
双向3338 分钟前
当Trae遇上高德MCP:一次国庆武汉之旅的AI技术实践
人工智能·trae
格林威38 分钟前
Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型和EasyOCR实现汽车牌照动态检测和识别(C#代码,UI界面版)
人工智能·深度学习·数码相机·yolo·c#·汽车·视觉检测
以泪为证39 分钟前
WebSocket 任务分发系统代码深度分析与应用
python