Python 3.6并行加载多文件至内存的最优方法及问题解决
搞定多进程并行加载pickle文件的问题
嘿,你的代码里藏着一个关键小错误,这就是为什么多进程没生效、程序还是串行跑的原因!
你看,调用pool.apply_async(load1(),)的时候,加了括号的load1()会立刻执行这个函数,等它加载完文件、返回结果后,才把结果传给apply_async——相当于三个加载函数还是一个接一个跑完的,进程池根本没发挥并行的作用!
修正后的代码示例
先把函数调用改成传递函数对象(去掉括号),如果你的加载函数需要参数(比如文件名),把参数放在apply_async的args参数里就行。这里给你调整后的完整代码:
import timeit from multiprocessing import Pool import pickle # 写通用的加载函数,不用重复写load1/load2/load3 def load_pickle(file_path): with open(file_path, 'rb') as f: return pickle.load(f) def loadMaps(): start = timeit.default_timer() # 6个文件的话,把这里的路径改成你的6个文件路径 file_paths = ['file1.pkl', 'file2.pkl', 'file3.pkl'] # 创建进程池,进程数设为文件数(你排除了IO限制,这样能最大化并行) with Pool(processes=len(file_paths)) as pool: # 提交所有加载任务,注意是传函数对象+参数,不是直接调用函数 tasks = [pool.apply_async(load_pickle, args=(path,)) for path in file_paths] # 如果需要获取加载后的字典,用get()方法逐个取出 loaded_dicts = [task.get() for task in tasks] stop = timeit.default_timer() print('loadFiles takes in %.1f seconds' % (stop - start)) # Windows系统必须加这个判断!否则多进程会出奇怪的错误 if __name__ == '__main__': loadMaps()
几个重要的小提示
- 为什么用with语句管理Pool? 这样不用手动写
pool.close()和pool.join(),with块结束后会自动处理,代码更简洁安全。 - 进程数怎么设? 你已经排除了IO限制,那进程数设为文件数(6个)就好,这样每个文件对应一个进程,刚好并行加载。
- Windows用户必看:Windows的多进程是spawn模式,必须把主执行逻辑放在
if __name__ == '__main__':下面,否则会重复创建进程,导致程序崩溃或者不工作。 - 代码复用性:用通用的
load_pickle函数代替多个load1/load2,后续加更多文件只需要修改file_paths列表就行,维护起来方便多了。
按照这个代码改完,应该就能真正实现并行加载,把时间压到100秒左右啦!
内容的提问来源于stack exchange,提问作者eSadr
相关产品推荐
相关产品推荐

