如何在目录树上进行递归遍历的多线程处理是一个好的方法?

3
我正在考虑一种针对目录树的多线程递归遍历的好方法。
我目前正在对根目录下的文件夹进行递归遍历,并在单独的线程中运行每个文件夹的遍历。
这样做虽然提高了性能,但仍存在“长尾”问题-大型文件夹需要很长时间。
有什么更好的方法吗?
我正在使用Python和Java。
谢谢。
编辑: 我不需要将文件加载到内存中。只需处理文件路径并可能获取一些元数据信息,如文件大小。

3
展示一些代码 / 你尝试了什么? / 确切的问题是什么? - Inbar Rose
不确定您之前尝试过什么,但是您是否首先将文件加载到内存中?这可能是一个I/O问题。如果您还没有尝试过,请先将文件夹加载到内存中。 - Matt Westlake
你们在生成线程方面有什么政策?如果你为每个子目录都生成一个新线程,那么很快你就会变得I/O受限,使每个线程都陷入困境,然后还将为你所看到的每个目录生成更多的线程,这将使你的整个机器陷入停顿。 - Mateusz Kowalczyk
我写了这样一段代码:获取给定根目录下的所有目录,并在单独的线程中对每个文件夹运行遍历代码。问题是,有没有更好的方法来实现多线程任务? - user1251654
@kw4nta - 不,我的意思是我已经用Java和Python编写了应用程序来实现我所说的功能。 - user1251654
显示剩余5条评论
2个回答

0

严格回答多线程问题,你可以制定一些规则来确定何时在递归中启动新线程,例如,每个偶数深度都会分裂成线程。请观察以下类似Python的伪代码:

depth = 0
while true:
    subDirCount = countSubDirs()
    if subDirCount = 0:
        break
    else:
        if depth % 2 = 0:
            for dir in subDirs:
                newThread(dir)
        else:
            for dir in subDirs:
                recurse(dir)

现在这个解决方案并没有解决你将会遇到的线程安全问题,但这是你能得到的最好的异步返回设置。


0

这是错误的方法,因为您不知道目录节点的深度和大小。即使您知道,使用多个线程迭代目录树本身也无法加速。您想要做的是在单个线程中迭代目录,并将您正在对文件/目录执行的工作提交给ExecutorService。 另请参见Executors


问题在于我只需要收集文件路径和一些元数据。性能在这里是一个问题,因为我有数千万个文件。从我所看到的情况来看,在单个线程上运行迭代比我的方法要慢得多。但是,假设我使用15个线程,整个过程需要20分钟(而不是单线程的60分钟)-其中8分钟仅由5个线程花费在非常大的目录上,因为所有其他线程都已经完成了。 - user1251654
现在我很好奇。在第一次迭代文件时,它应该只受IO限制和寻道时间的影响。在第二次迭代中,在一个理智的操作系统上,所有东西都应该在缓存中。你能否重新运行你的基准测试,而不访问任何元数据,只收集文件路径?因为我尝试过使用Fork/Join API(Java 7),但多个线程的结果只会更糟。此外,使用Profile运行可能很有趣,以查看时间消耗在哪里。 - poison
  1. 你说的缓存是哪个?
  2. 需要注意的是这些路径都是网络路径 - \server1\path... 所以也许网络开销会导致更多线程更有效率。
- user1251654
  1. VFS的目录缓存
  2. 好的,我没有考虑到网络文件系统。Fork/Join API可能适合你:http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html
- poison

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接