如何优化50万+文件的文档计数程序?线程/多进程是否可行?
优化方案:50万+文件的文档统计提速
先修复原代码的基础问题
原代码存在几个拖慢速度且导致统计错误的问题:
- 每次循环重复调用
build_paths()生成目录列表,完全没必要 file_list未在每个站点目录遍历后清空,统计的是累计总数而非单个站点的数量- 用
rglob('*.doc*')会匹配大量无关文件(比如.docm、.doc.bak),后续再过滤后缀做了无用功
先修正这些问题,单线程就能提升不少速度:
from pathlib import Path def build_paths(): """Build list of all site Uploaded Files dirs""" return list(Path(r"K:\BigDog").glob(r'*\Data\Files')) def count_doc_files(doc_list): """Count doc and docx files for Live sites.""" file_dict = {} target_dirs = build_paths() # 只生成一次目录列表 for dir_path in target_dirs: site = dir_path.parts[3] # 直接统计符合后缀的文件数量,无需收集所有文件名 count = 0 # 分别遍历两种后缀,避免匹配无关文件 for suffix in doc_list: count += sum(1 for _ in dir_path.rglob(f"*{suffix}")) file_dict[site] = count return file_dict doc_list = ['.doc', '.docx'] print(count_doc_files(doc_list))
并行提速:多线程是更优选择
遍历大量文件属于IO密集型任务,此时多线程比多进程更合适——多进程的进程切换开销远大于线程,而IO等待时Python的GIL会释放,线程可以充分利用空闲时间。
用concurrent.futures.ThreadPoolExecutor实现多线程并行,每个目录单独统计后汇总结果:
from pathlib import Path from concurrent.futures import ThreadPoolExecutor def build_paths(): return list(Path(r"K:\BigDog").glob(r'*\Data\Files')) def count_single_dir(dir_path, doc_list): """单个目录的文件统计逻辑""" site = dir_path.parts[3] count = 0 for suffix in doc_list: count += sum(1 for _ in dir_path.rglob(f"*{suffix}")) return (site, count) def count_doc_files_parallel(doc_list, max_workers=4): target_dirs = build_paths() file_dict = {} # 用线程池并行处理每个目录 with ThreadPoolExecutor(max_workers=max_workers) as executor: futures = [executor.submit(count_single_dir, dir_path, doc_list) for dir_path in target_dirs] # 收集所有结果 for future in futures: site, count = future.result() file_dict[site] = count return file_dict doc_list = ['.doc', '.docx'] print(count_doc_files_parallel(doc_list))
额外提速建议
- 调整
max_workers:不用设太大,Windows下4-8个线程足够,过多线程反而会因文件系统竞争拖慢速度 - 关闭Windows Defender实时监控:本地磁盘的杀毒软件实时扫描会严重拖慢文件遍历速度
- 用
os.scandir()替代pathlib.rglob():底层的os.scandir()遍历速度更快,尤其是深度目录场景,可改写遍历逻辑进一步提速
内容的提问来源于stack exchange,提问作者FancyPantsFlower
相关产品推荐
相关产品推荐

