You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python多进程反复处理大图片列表:避免重复拷贝列表的优化方案

问题场景

我有一个包含约20000张图片的大列表list_img,需要用参数列表params中的不同参数反复处理它。要求用多进程实现,且所有进程先完成arg1对图片分片的处理,再用arg2处理,依此类推。由于params中各参数的处理时间差异极大,如果按参数分配进程(比如核心1处理arg1、核心2处理arg2),会出现多数进程提前闲置、仅少数进程仍在运算的情况。

当前的可行实现代码如下:

from multiprocessing import Pool
import numpy as np

def calc_image(argument, image):
    val = argument * image    # 仅为演示,非真实处理逻辑
    return val

if __name__ == "__main__":
    pool = Pool(processes=8)
    list_img = [np.ones((100, 100))] * 20000    # 演示用数据
    params = list(range(100))    # 演示用参数列表
    for par in params:
        par_list = [par] * len(list_img)
        return_vals = pool.starmap(calc_image, zip(par_list, list_img))
    pool.close()

需要解决的问题:如何避免循环中每次更换参数par时都拷贝list_img?同时尽可能不使用全局变量。


方案1:利用进程池初始化器加载本地图片列表

通过Pool的initializer和initargs参数,在子进程启动时一次性将list_img加载到每个进程的本地内存,后续处理仅传递参数,无需重复拷贝图片列表。

修改后的代码:

from multiprocessing import Pool
import numpy as np

# 子进程本地存储的图片列表,仅在子进程内有效
local_imgs = None

def init_worker(imgs):
    global local_imgs
    local_imgs = imgs

def calc_image(argument):
    # 直接使用子进程本地的图片列表处理
    return [argument * img for img in local_imgs]

if __name__ == "__main__":
    list_img = [np.ones((100, 100))] * 20000
    params = list(range(100))
    
    # 初始化进程池时传入图片列表,每个子进程仅加载一次
    with Pool(processes=8, initializer=init_worker, initargs=(list_img,)) as pool:
        results = pool.map(calc_image, params)
  • 优势:仅在进程启动时完成一次图片列表拷贝,后续参数循环无额外拷贝开销;子进程内的全局变量不影响主进程,符合“尽可能不使用全局变量”的要求。

方案2:使用共享内存存储图片(适用于numpy数组场景)

如果图片以numpy数组形式存储,可通过multiprocessing.Array创建共享内存对象,让所有子进程共享同一块内存区域的图片数据,彻底避免拷贝。

示例代码:

from multiprocessing import Pool, Array
import numpy as np

def calc_image(argument, shape, dtype):
    # 从共享内存中恢复完整的图片数组
    shared_arr = np.frombuffer(shared_imgs.get_obj(), dtype=dtype).reshape(shape)
    return argument * shared_arr

if __name__ == "__main__":
    # 构造演示用的批量图片数组(实际对应20000张图片)
    img_shape = (20000, 100, 100)
    img_dtype = np.float64
    list_img = np.ones(img_shape, dtype=img_dtype)
    
    # 创建共享内存数组,lock=False表示无需进程同步(只读场景)
    shared_imgs = Array('d', list_img.size, lock=False)
    # 将图片数据写入共享内存
    np.frombuffer(shared_imgs.get_obj(), dtype=img_dtype)[:] = list_img.flatten()
    
    params = list(range(100))
    
    with Pool(processes=8) as pool:
        # 仅传递参数、图片形状和数据类型,子进程从共享内存读取图片
        results = pool.starmap(calc_image, [(par, img_shape, img_dtype) for par in params])
  • 优势:完全无拷贝,内存利用率最高;适合大规模数值型图片数据处理。

方案3:用functools.partial绑定图片列表(轻量场景可选)

通过functools.partial将图片列表绑定到处理函数上,进程池初始化时完成一次拷贝,后续仅传递参数。

示例代码:

from multiprocessing import Pool
import numpy as np
from functools import partial

def calc_image(argument, imgs):
    return [argument * img for img in imgs]

if __name__ == "__main__":
    list_img = [np.ones((100, 100))] * 20000
    params = list(range(100))
    
    # 将图片列表绑定到处理函数,生成新的函数
    bound_calc = partial(calc_image, imgs=list_img)
    
    with Pool(processes=8) as pool:
        results = pool.map(bound_calc, params)
  • 优势:无需使用全局变量,代码简洁;但本质是进程启动时的一次性拷贝,内存占用与方案1相当,适合轻量场景。

内容的提问来源于stack exchange,提问作者RaJa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 14:24:51