2 回答
TA贡献1851条经验 获得超3个赞
我无法完全按照我的意愿工作。os.walk 很慢,我想到的所有其他方法要么速度相似,要么由于线程太多而崩溃。
我最终使用了我在上面发布的类似方法,但不是在顶级目录开始递归,而是向下一层或两层,直到有几个目录。然后它将在这些目录中的每一个串行开始递归,这限制了足以成功完成的线程数。执行时间与 os.walk 类似,这可能会使实现更简单、更易读。
TA贡献1862条经验 获得超7个赞
不要鄙视池的用处,尤其是当您想控制要创建的进程数量时。他们还负责管理您的工作人员(创建/启动/加入/分配工作块)并帮助您收集潜在结果。
正如您自己意识到的那样,您创建了太多进程,以至于您似乎耗尽了如此多的系统资源而无法创建更多进程。
此外,在代码中创建新进程受外部因素控制,即文件树中的文件夹数,这使得限制进程数变得非常困难。此外,创建新进程会在操作系统上带来相当大的开销,您甚至可能最终将这些开销浪费在空目录上。另外,进程之间的上下文切换非常昂贵。
根据您创建的进程数量,考虑到您声明的文件夹数量,您的进程基本上只会坐在那里闲置,而他们正在等待 CPU 时间份额来实际执行某些工作。除非您拥有一台拥有数千个内核的超级计算机,否则对于上述 CPU 时间会有很多争用。即使一个进程获得了一些 CPU 时间来工作,它也可能会花费相当多的时间来等待 I/O。
话虽如此,您可能想要研究使用线程来完成这样的任务。你可以在你的代码中做一些优化。从您的示例中,我看不出有任何理由将识别要复制的文件和实际将它们复制到不同的任务中。为什么不让您的员工立即复制他们发现与 RE 匹配的每个文件?
我会使用os.walk(我认为相当快)从主线程中创建有问题的目录中的文件列表,然后将该列表卸载到工作人员池,检查这些文件是否匹配并立即复制这些文件:
import os
import re
from multiprocessing.pool import ThreadPool
search_dirs = ["dir 1", "dir2"]
ptn = re.compile(r"your regex")
# your target dir definition
file_list = []
for topdir in search_dirs:
for root, dirs, files in os.walk(topdir):
for file in files:
file_list.append(os.path.join(root, file))
def copier(path):
if ptn.match(path):
# do your shutil.copyfile with the try-except right here
# obviously I did not want to start mindlessly copying around files on my box :)
return path
with ThreadPool(processes=10) as pool:
results = pool.map(copier, file_list)
# print all the processed files. For those that did not match, None is returned
print("\n".join([r for r in results if r]))
附带说明:不要手动连接您的路径 ( file[0] + "\\" + file[1]),而是os.path.join用于此。
添加回答
举报