多任务执行CPU密集型操作仅占10%CPU?寻求原因排查
问题:CPU密集型HTML解析任务CPU负载仅10%的原因排查
我使用24线程的5900X CPU,启动20个Task执行一项本应完全属于CPU密集型的HTML解析操作,但CPU负载最高仅达到10%。想了解是对Task线程模型的理解有误,还是HtmlAgilityPack库存在问题?
相关示例代码:
public async static Task TestHtmlAgilityPack(bool loadHtml = true) { // "basePath" is a folder has approx 20 folders each containing approx 3000 files (20 tasks * 3,000 files = 60k overall) var dirs = Directory.GetDirectories(basePath); List<Task> tasks = new(); var strs = new ConcurrentBag<string>(); foreach (var dir in dirs) { tasks.Add(Task.Run(() => { foreach (var file in Directory.GetFiles(dir, "*.html")) // Each of the 20 tasks processes approx 3000 files { var html = File.ReadAllText(file); strs.Add(html.Substring(1, 1000)); if (loadHtml) { var doc = new HtmlDocument(); doc.LoadHtml(html); } } })); } await Task.WhenAll(tasks); Console.WriteLine(strs.Last()); }
已知条件:
- 不启用LoadHtml时,操作15秒完成,IO访问时间可忽略。
- 启用LoadHtml后耗时20分钟,但CPU负载峰值仅10%,远低于24线程CPU运行20个CPU密集型任务预期的约80%。
分析与排查方向
核心原因大概率是
ConcurrentBag<string>的锁竞争:strs.Add是线程安全操作,但当20个线程同时高频调用该方法时,会产生严重的锁竞争——大量线程会处于等待锁释放的状态,而非执行CPU密集的解析逻辑,直接拉低整体CPU利用率。
验证方法:注释掉strs.Add(html.Substring(1, 1000));这一行后重新测试,若CPU负载明显上升,即可确认锁竞争是问题根源。HtmlAgilityPack的潜在同步瓶颈:
部分版本的HtmlAgilityPack在解析过程中可能存在全局锁或共享资源的同步逻辑,导致多线程无法真正并行执行解析操作。但这个概率低于锁竞争,建议先排除锁竞争问题后再验证。Task线程调度的小概率影响:
虽然20个Task理论上能填满24线程的CPU,但如果线程池因历史操作残留(比如之前的IO线程未及时回收)导致线程分配不足,也可能影响负载。但结合你IO可忽略的前提,这个可能性极低。
内容的提问来源于stack exchange,提问作者Zak123
相关产品推荐
相关产品推荐

