如何在Python中并行运行os.walk?

use*_*654 23 python

我在Java中编写了一个简单的应用程序,它采用路径列表并生成一个包含该原始列表下所有文件路径的文件.

如果我有paths.txt有:

c:\folder1\
c:\folder2\
...
...
c:\folder1000\
Run Code Online (Sandbox Code Playgroud)

我的应用程序在每个多线程路径上运行递归函数,并返回包含这些文件夹下所有文件路径的文件.

现在我想用Python编写这个应用程序.

我写了一个简单的应用程序,用于os.walk()运行给定的文件夹并打印文件路径输出.

现在我想并行运行它,我已经看到Python有一些模块:多线程和多处理.

什么是最好的做什么?在这种方式下,它是如何执行的?

Ray*_*ger 25

这是一个多处理解决方案:

from multiprocessing.pool import Pool
from multiprocessing import JoinableQueue as Queue
import os

def explore_path(path):
    directories = []
    nondirectories = []
    for filename in os.listdir(path):
        fullname = os.path.join(path, filename)
        if os.path.isdir(fullname):
            directories.append(fullname)
        else:
            nondirectories.append(filename)
    outputfile = path.replace(os.sep, '_') + '.txt'
    with open(outputfile, 'w') as f:
        for filename in nondirectories:
            print >> f, filename
    return directories

def parallel_worker():
    while True:
        path = unsearched.get()
        dirs = explore_path(path)
        for newdir in dirs:
            unsearched.put(newdir)
        unsearched.task_done()

# acquire the list of paths
with open('paths.txt') as f:
    paths = f.split()

unsearched = Queue()
for path in paths:
    unsearched.put(path)

pool = Pool(5)
for i in range(5):
    pool.apply_async(parallel_worker)

unsearched.join()
print 'Done'
Run Code Online (Sandbox Code Playgroud)

  • @static_rtti为什么会这么重要?并行化的目的是加速整个任务.更精细的并行化通常比课程粒度更昂贵.此外,它需要你打破*os.walk()*抽象并基本上重写它的一些代码(抛弃首先拥有库的好处).此外,并行化步行本身并没有多大好处,因为这是一个I/O绑定操作. (2认同)
  • @static_rtti另一个想法.OP在评论中表示他正在使用可以并行运行的多个网络驱动器.因此,速度优势来自并行运行多个步行任务.如果您尝试并行化行走本身,则没有任何好处,因为单个驱动器上的读/写臂一次只能做一件事. (2认同)
  • os.walk() 在递归之前产生一次。*break* 确保它永远不会进入递归阶段。代码是正确的。如果它让您烦恼,请使用 os.path.isdir() 手动将 os.listdir() 拆分为目录和文件。这就是 os.walk() 内部所做的事情。OP的问题已经得到了公正的回答。现在,是你履行职责的时候了。 (2认同)

lod*_*ode 6

这是python中的线程模式,对我有用.由于线程在CPython中的工作方式,我不确定线程​​是否会提高性能.

import threading
import Queue
import os

class PathThread (threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.queue = queue

    def printfiles(self, p):
        for path, dirs, files in os.walk(p):
            for f in files:
                print path + "/" + f

    def run(self):
        while True:
            path = self.queue.get()
            self.printfiles(path)
            self.queue.task_done()

# threadsafe queue
pathqueue = Queue.Queue()
paths = ["foo", "bar", "baz"]

# spawn threads
for i in range(0, 5):
    t = PathThread(pathqueue)
    t.setDaemon(True)
    t.start()

# add paths to queue
for path in paths:
    pathqueue.put(path)

# wait for queue to get empty
pathqueue.join()
Run Code Online (Sandbox Code Playgroud)

  • @RaymondHettinger不适用于IO,但:) (6认同)
  • 并行化的线程化方法可能会适得其反.Python的全局解释器锁将阻止任何两个线程同时运行. (5认同)
  • @RaymondHettinger在这种情况下,很明显是对的。您在重复GIL的谎言。GIL不阻止阻塞操作,I / O,并且在许多情况下,处理发生在GIL之外。不要误会我的意思,GIL很烂,但是这并不会使Python中的多线程一文不值。 (2认同)