如何将Python高内存占用包置于共享内存供其他程序导入以降低多进程内存消耗?
在多进程场景下共享Python高内存包以降低内存占用的方法
在多进程环境中,重复导入高内存占用的Python包会导致内存冗余,以下是几种实用的解决方案:
1. 利用Unix/Linux的写时复制(COW)特性
Unix类系统(Linux/macOS)的进程fork机制自带写时复制特性:父进程先导入大模块,再创建子进程,子进程会共享父进程的内存页,只有当内存页被修改时才会复制。这是最简单的共享方式,无需额外代码改造。
示例代码:
import multiprocessing import numpy as np # 高内存包在父进程提前导入 def worker(): # 子进程直接使用已导入的模块,无需重复加载 print(np.mean(np.random.rand(1000, 1000))) if __name__ == "__main__": # 创建4个子进程,共享父进程中已加载的np模块内存 processes = [multiprocessing.Process(target=worker) for _ in range(4)] for p in processes: p.start() for p in processes: p.join()
注意事项:
- Windows系统不支持COW,该方法无效
- 不要修改模块的全局属性(如
np.some_attr = value),否则会触发内存页复制,失去共享效果
2. 使用Python内置的multiprocessing.shared_memory(3.8+)
对于需要跨进程主动共享特定数据的场景,可以利用shared_memory将模块的核心数据(如预训练模型权重、大型数组)存入共享内存区域,让子进程直接读取,避免重复加载整个包。
示例代码:
import multiprocessing from multiprocessing import shared_memory import pickle import numpy as np def init_shared_data(): # 父进程加载大数据并序列化 large_array = np.random.rand(2000, 2000) serialized_data = pickle.dumps(large_array) # 创建共享内存并写入数据 shm = shared_memory.SharedMemory(create=True, size=len(serialized_data)) shm.buf[:len(serialized_data)] = serialized_data return shm.name, len(serialized_data) def worker(shm_name, data_size): # 子进程通过共享内存名称获取数据 existing_shm = shared_memory.SharedMemory(name=shm_name) serialized_data = existing_shm.buf[:data_size] large_array = pickle.loads(serialized_data) print(f"子进程获取到的数据形状:{large_array.shape}") existing_shm.close() if __name__ == "__main__": shm_name, data_size = init_shared_data() processes = [ multiprocessing.Process(target=worker, args=(shm_name, data_size)) for _ in range(4) ] for p in processes: p.start() for p in processes: p.join() # 清理共享内存 shm = shared_memory.SharedMemory(name=shm_name) shm.close() shm.unlink()
注意事项:
- 仅适合提取可序列化的核心数据,不适合状态复杂的模块
- 需要自行处理序列化/反序列化的性能开销
3. 基于内存映射文件(mmap)的共享
将模块的核心数据写入磁盘文件,再通过mmap让多个进程映射该文件到内存,实现内存共享。这种方式无需占用额外的进程内存,适合超大规模数据。
示例代码:
import multiprocessing import mmap import pickle import numpy as np import os def write_mmap_file(): # 将大数据序列化后写入文件 large_data = np.random.rand(3000, 3000) serialized_data = pickle.dumps(large_data) with open("shared_data.bin", "wb") as f: f.write(serialized_data) return len(serialized_data) def worker(file_size): # 子进程映射文件到内存并读取数据 with open("shared_data.bin", "rb") as f: with mmap.mmap(f.fileno(), length=file_size, access=mmap.ACCESS_READ) as mm: large_data = pickle.loads(mm[:file_size]) print(f"子进程计算数据总和:{large_data.sum():.2f}") if __name__ == "__main__": file_size = write_mmap_file() processes = [ multiprocessing.Process(target=worker, args=(file_size,)) for _ in range(4) ] for p in processes: p.start() for p in processes: p.join() # 清理临时文件 os.unlink("shared_data.bin")
注意事项:
- 适合数据不频繁修改的场景,修改数据会同步到磁盘
- 首次加载存在磁盘IO开销,但后续访问直接从内存映射读取
内容的提问来源于stack exchange,提问作者frank
相关产品推荐
相关产品推荐

