.NET Core 6中如何加速PDF文件搜索循环?
性能优化方案
针对你当前的PDF搜索方法在处理1500个PDF文件+200个关键词时的性能瓶颈,从以下几个核心方向优化:
关键优化点
1. 提前预处理关键词,消除重复计算
当前代码在每个PDF的每个页面循环里重复执行keyword.ToLower().Trim(),完全可以在方法开头只做一次预处理:
// 方法入口处统一处理关键词,避免重复计算 var normalizedKeyword = keyword.ToLower().Trim();
2. 优先检查文件名/路径,跳过无意义的PDF解析
如果文件名或文件路径已经匹配关键词,直接加入结果,不需要再解析PDF内容,大幅节省磁盘IO和解析时间:
// 先判断文件名/路径是否匹配,匹配则直接加入结果并跳过后续逻辑 var fileLowerName = file.Name.ToLower(); var fileLowerFullPath = file.FullName.ToLower(); if (fileLowerName.Contains(normalizedKeyword) || fileLowerFullPath.Contains(normalizedKeyword)) { results.Add(new KeyValuePair<string, string>(keyword, file.FullName)); continue; }
3. 匹配到关键词后立即终止页面遍历
单个PDF只要有一个页面匹配关键词,就无需继续遍历剩余页面,直接跳出循环:
using (var document = new PdfDocument(file.FullName)) { foreach (var page in document.Pages) { var textLower = page.ExtractText().ToLower(); if (textLower.Contains(normalizedKeyword)) { results.Add(new KeyValuePair<string, string>(keyword, file.FullName)); break; // 找到匹配后立刻停止页面遍历 } } }
4. 控制并发度,避免磁盘IO冲突
Parallel.ForEach默认会占用全部CPU核心,但PDF搜索属于IO密集型任务,过高并发会导致磁盘读写拥堵。手动设置合理的并发上限:
// 根据磁盘性能调整,机械硬盘建议设2-4,固态硬盘可设为CPU核心数 Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, file => { // 核心处理逻辑 });
5. 及时释放PDF资源,防止内存泄漏
使用using包裹PdfDocument,确保文件流和内存资源及时释放,避免内存占用过高影响后续性能:
using (var document = new PdfDocument(file.FullName)) { // 页面遍历与内容检查逻辑 }
6. 批量处理关键词(最核心的性能提升)
如果当前是循环调用SearchPdf处理200个关键词,会重复遍历1500个PDF200次,这是最大的性能浪费。改成一次遍历所有PDF,同时检查所有关键词:
public static ConcurrentBag<KeyValuePair<string, string>> SearchPdf(string path, List<string> keywords) { var results = new ConcurrentBag<KeyValuePair<string, string>>(); // 提前预处理所有关键词 var normalizedKeywords = keywords.Select(k => k.ToLower().Trim()).ToList(); var directory = new DirectoryInfo(path); var files = directory.GetFiles("*.pdf", SearchOption.AllDirectories); Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, file => { var fileLowerName = file.Name.ToLower(); var fileLowerFullPath = file.FullName.ToLower(); var matchedKeywords = new List<string>(); // 先检查文件名匹配的关键词 foreach (var kw in normalizedKeywords) { if (fileLowerName.Contains(kw) || fileLowerFullPath.Contains(kw)) { matchedKeywords.Add(kw); } } // 添加文件名匹配的结果 foreach (var kw in matchedKeywords) { results.Add(new KeyValuePair<string, string>(kw, file.FullName)); } // 过滤已匹配的关键词,只处理剩余的 var remainingKeywords = normalizedKeywords.Except(matchedKeywords).ToList(); if (!remainingKeywords.Any()) return; // 解析PDF内容检查剩余关键词 using (var document = new PdfDocument(file.FullName)) { foreach (var page in document.Pages) { var textLower = page.ExtractText().ToLower(); var foundKeywords = remainingKeywords.Where(kw => textLower.Contains(kw)).ToList(); foreach (var kw in foundKeywords) { results.Add(new KeyValuePair<string, string>(kw, file.FullName)); remainingKeywords.Remove(kw); } if (!remainingKeywords.Any()) break; // 所有关键词都匹配,停止遍历页面 } } }); return results; }
优化效果说明
- 把200次PDF遍历压缩为1次,直接减少99%的磁盘IO开销
- 提前过滤匹配的文件/关键词,避免大量无意义的PDF内容解析
- 控制并发度避免磁盘拥堵,同时及时释放资源稳定内存占用
内容的提问来源于stack exchange,提问作者micex
相关产品推荐
相关产品推荐

