首页 > 解决方案 > 使用 python 3.6 将多个文件并行加载到内存中的最佳方法是什么?

问题描述

我有 6 个大文件,每个文件都包含一个字典对象,我使用 pickle 函数将其保存在硬盘中。按顺序加载所有这些大约需要 600 秒。我想同时开始加载所有这些以加快进程。假设它们都具有相同的大小,我希望在 100 秒内加载它们。我使用 multiprocessing 和 apply_async 分别加载它们中的每一个,但它像顺序一样运行。这是我使用的代码,它不起作用。该代码适用于其中 3 个文件,但其中 6 个文件相同。我将第三个文件放在另一个硬盘中以确保 IO 不受限制。

def loadMaps():    
    start = timeit.default_timer()
    procs = []
    pool = Pool(3)
    pool.apply_async(load1(),)
    pool.apply_async(load2(),)
    pool.apply_async(load3(),)
    pool.close()
    pool.join()
    stop = timeit.default_timer()
    print('loadFiles takes in %.1f seconds' % (stop - start))

标签: pythonpython-3.xparallel-processingpython-multiprocessingpython-asyncio

解决方案


如果您的代码主要受 IO 限制并且文件位于多个磁盘上,您可以使用线程来加速它:

import concurrent.futures
import pickle

def read_one(fname):
    with open(fname, 'rb') as f:
        return pickle.load(f)

def read_parallel(file_names):
    with concurrent.futures.ThreadPoolExecutor() as executor:
        futures = [executor.submit(read_one, f) for f in file_names]
        return [fut.result() for fut in futures]

GIL不会强制 IO 操作序列化运行,因为 Python 在执行 IO 时会始终释放它。

关于替代品的几点评论:

  • multiprocessing不太可能有帮助,因为虽然它保证在多个进程中完成工作(因此没有 GIL),但它还需要在子进程和主进程之间传输内容,这需要额外的时间。

  • asyncio根本不会帮助您,因为它本身不支持异步文件系统访问(流行的操作系统也不支持)。虽然它可以用线程来模拟它,但效果和上面的代码一样,只是多了一些仪式。

  • 这两个选项都不会将六个文件的加载速度提高六倍。考虑到至少有一些时间花在创建字典上,这些字典将由 GIL 序列化。如果您想真正加快启动速度,更好的方法是不要预先创建整个字典并切换到文件内数据库,可能使用字典来缓存对其内容的访问。


推荐阅读