并行目录walk python

时间:2015-04-13 20:35:21

标签: python multithreading parallel-processing

我需要从给定的根位置开始读取目录树中的每个文件。我想尽可能快地使用并行性来做到这一点。我有48个内核和1 TB内存,所以线程资源不是问题。我还需要记录每个已读取的文件。

我查看了使用joblib,但无法将joblib与os.walk结合使用。

我可以想到两种方式:

  • 遍历树并将所有文件添加到队列或列表中,并使工作线程队列出队列文件 - 最佳负载平衡,可能由于初始步行而导致更多时间。队列开销
  • 生成线程并静态地为每个线程分配树的部分 - 低负载平衡,没有初始步行,根据某种哈希值分配目录。

还是有更好的方法吗?

编辑存储的性能不是问题。假设有一个无限快速的存储,可以处理无限数量的并行读取

编辑删除多节点情况以保持对并行目录步行的关注

1 个答案:

答案 0 :(得分:5)

最简单的方法可能是使用multiprocessing.Pool来处理主进程中执行的os.walk的结果输出。

这假定您要并行化的主要工作是对单个文件进行的任何处理,而不是递归扫描目录结构的工作。如果您的文件很小并且您不需要对其内容进行大量处理,则可能不是这样。我还假设multiprocessing为您处理的流程创建将能够在您的群集上正确分配负载(这可能是也可能不是)。

import itertools
import multiprocessing

def worker(filename):
    pass   # do something here!

def main():
    with multiprocessing.Pool(48) as Pool: # pool of 48 processes

        walk = os.walk("some/path")
        fn_gen = itertools.chain.from_iterable((os.path.join(root, file)
                                                for file in files)
                                               for root, dirs, files in walk)

        results_of_work = pool.map(worker, fn_gen) # this does the parallel processing

以这种方式并行化工作完全有可能比仅在单个进程中完成工作要慢。这是因为共享文件系统底层硬盘上的IO可能是瓶颈,如果磁盘需要更频繁地寻找而不是读取更长的线性数据部分,并行尝试多次磁盘读取会使它们变得更慢。即使IO速度稍快,进程之间通信的开销也可能会耗尽所有收益。