如何通过池化作业并行生成多幅Matplotlib地图?
高效批量生成区域地图解决方案
问题背景
现有Matplotlib+Cartopy绘图脚本,需为多组经纬度范围批量生成区域地图。当前并行多次运行脚本的方式会重复加载大体积shapefile,导致内存占用高、效率低下,需求是实现仅加载一次shapefile的池化并行绘图方案。
核心思路
利用Python的multiprocessing.Pool实现进程池并行:在主进程中提前加载shapefile等公共资源,通过全局变量传递给子进程,避免重复加载;子进程仅负责接收区域参数、绘制并保存单张地图,最大化复用公共资源。
具体实现步骤与代码示例
from matplotlib import pyplot as plt, gridspec import cartopy.crs as crs from cartopy.io.shapereader import Reader from cartopy.feature import ShapelyFeature import multiprocessing as mp # ---------------------- 主进程预加载公共资源 ---------------------- # 仅执行一次,所有子进程共享该资源 states_path = '/some/path/usstates.shp' reader = Reader(states_path) states_geoms = list(reader.geometries()) # 提前读取几何数据到内存 crs_proj = crs.LambertConformal() states_feature = ShapelyFeature(states_geoms, crs_proj, facecolor='none', edgecolor='black') # 切换为非交互式后端,避免多进程下Matplotlib GUI冲突 plt.switch_backend('Agg') # ---------------------- 单区域绘图函数 ---------------------- def plot_region(extent, save_path): # 创建独立的绘图实例,避免子进程间资源冲突 fig = plt.figure(figsize=(14,9)) gs = gridspec.GridSpec(ncols=1, nrows=2, width_ratios=[1], height_ratios=[0.15, 3.00]) gs.update(wspace=0.00, hspace=0.00) # 绘制顶部文本轴 ax1 = fig.add_subplot(gs[0, :]) ax1.text(0.00, 0.50, "Some Fun Text", fontsize=15) ax1.text(1.00, 0.50, "Some Other Fun Text", fontsize=15, ha='right') ax1.axis('off') # 关闭轴元素,消除多余边框 # 绘制地图轴 ax2 = fig.add_subplot(gs[1, :], projection=crs_proj) ax2.set_extent(extent, crs=crs_proj) ax2.add_feature(states_feature, linewidth=1.25) # 保存图像并释放资源 plt.savefig(save_path, dpi=100, bbox_inches='tight') plt.close(fig) # 必须关闭,防止内存泄漏 # ---------------------- 批量并行执行 ---------------------- if __name__ == '__main__': # 示例:多组区域范围与对应保存路径 region_tasks = [ ([lon1_min, lon1_max, lat1_min, lat1_max], './region1.png'), ([lon2_min, lon2_max, lat2_min, lat2_max], './region2.png'), # 添加更多区域任务... ] # 启动进程池,进程数建议设为CPU核心数 with mp.Pool(processes=mp.cpu_count()) as pool: # 用starmap传递多参数任务 pool.starmap(plot_region, region_tasks)
关键优化说明
- 公共资源复用:shapefile的几何数据和
ShapelyFeature在主进程仅加载一次,所有子进程直接复用,彻底避免重复IO和内存冗余。 - 独立绘图上下文:每个子进程创建专属
figure对象,完成后立即关闭,避免跨进程资源冲突和内存泄漏。 - 非交互式后端:
Agg后端禁用GUI渲染,解决多进程下Matplotlib的线程安全问题。 - 进程池复用:
multiprocessing.Pool复用子进程,减少进程创建与销毁的额外开销。
内容的提问来源于stack exchange,提问作者TornadoEric
相关产品推荐
相关产品推荐

