执行指定C#代码时CPU占用过高问题排查求助
排查C#代码导致CPU峰值问题
问题代码
public bool CheckIfValidSignedPdfExists(string fileServerPath, int memberagreementId) { var filePaths = Directory.GetFiles(fileServerPath); if (filePaths.Length < 2) { return false; } var fileInfo = new List<FileInfo>(); foreach (var path in filePaths) { if (File.Exists(path)) fileInfo.Add(new FileInfo(path)); } if (fileInfo.Count < 2) return false; else { fileInfo = fileInfo.OrderByDescending(x => x.LastWriteTimeUtc).Take(2).ToList(); //Rules: 1. Name 2.size 3. Last write time 4. Extension var firstPdf = fileInfo.FirstOrDefault(); var lastPdf = fileInfo.LastOrDefault(); var firstFileNameCheck = string.Concat(Convert.ToString(memberagreementId), ".pdf"); var lastFileNameCheck = lastPdf.Name.StartsWith(Convert.ToString(memberagreementId) + "-") && lastPdf.Name.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase); if ((firstPdf.Name.Equals(firstFileNameCheck, StringComparison.OrdinalIgnoreCase)) && (lastFileNameCheck) && (firstPdf.Length > lastPdf.Length) && (firstPdf.LastWriteTimeUtc >= lastPdf.LastWriteTimeUtc)) return true; else return false; } }
问题现象
运行上述代码时,CPU出现明显峰值,监控显示高CPU线程与这段代码直接关联,同时存在明确的CPU尖峰波动。
问题排查与分析
- 全量文件枚举的开销:
Directory.GetFiles会一次性加载目录下所有文件的路径到内存,若目标目录包含大量文件(尤其是网络共享目录),该操作会阻塞线程并消耗大量CPU资源,IO延迟还会加剧线程调度的开销。 - 冗余的文件存在性检查:
Directory.GetFiles返回的路径本身已保证存在(枚举期间文件被删除的极端情况除外),额外的File.Exists(path)检查重复发起IO请求,累积增加CPU和IO负载。 - 全量排序的高复杂度:代码对目录下所有
FileInfo实例按LastWriteTimeUtc排序,排序算法的时间复杂度为O(n log n),当文件数量较多时,该操作会成为CPU消耗的核心点。 - 网络路径的IO放大效应:若
fileServerPath是网络共享路径,文件系统操作的延迟会大幅增加,线程在等待IO时的上下文切换会进一步推高CPU使用率。
优化建议
- 改用延迟枚举减少内存占用:用
Directory.EnumerateFiles替代Directory.GetFiles,它会逐个返回文件路径,无需一次性加载所有数据到内存。 - 提前过滤目标文件:枚举时直接筛选与
memberagreementId相关的PDF文件,减少后续处理的数据量:var targetIdStr = memberagreementId.ToString(); var relevantFiles = Directory.EnumerateFiles(fileServerPath, "*.pdf") .Where(path => Path.GetFileName(path).Equals($"{targetIdStr}.pdf", StringComparison.OrdinalIgnoreCase) || Path.GetFileName(path).StartsWith($"{targetIdStr}-", StringComparison.OrdinalIgnoreCase)) .Select(path => new FileInfo(path)) .ToList(); - 移除冗余的存在性检查:删除
File.Exists(path)的判断,避免重复IO操作。 - 缩小排序范围:仅对筛选后的目标文件排序,而非全目录文件,大幅降低排序的CPU开销。
- 添加缓存机制:若该方法被频繁调用,可缓存目标文件的元数据(如文件名、修改时间、大小),定期刷新缓存,避免重复的IO和计算操作。
内容的提问来源于stack exchange,提问作者Puneet
相关产品推荐
相关产品推荐

