为什么HtmlAgilityPack调用LoadHtml后出现CPU占用过高、死循环问题?
问题根源
你遇到的是HtmlAgilityPack 1.11.22版本的已知Bug,CPU占满的直接原因是非线程安全的Dictionary出现了链表环导致无限循环。
具体触发逻辑
- 该版本的
SetIdForNode方法内部使用Dictionary存储HTML节点的ID映射,但没有做并发安全校验,当多线程同时调用LoadHtml解析内容时,多个线程同时写入同一个Dictionary会破坏哈希表的内部结构,生成循环链表,后续的Insert操作会永远遍历这个链表,直接表现就是线程卡住、CPU占用持续100%。你的调用栈最终停在Dictionary.Insert方法,完全符合这个故障的特征。 - 即使是单线程场景,如果输入的畸形内容包含大量重复ID,也有概率触发该逻辑异常。你提到会处理非HTML格式的字符串,这类畸形内容更容易触发ID处理的异常逻辑。
解决方案
- 优先升级HtmlAgilityPack到1.11.46及以上版本,官方已经修复了
SetIdForNode方法的并发安全问题和字典循环漏洞。 - 如果暂时无法升级,在初始化
HtmlDocument后关闭ID跟踪功能,从根源上跳过SetIdForNode执行逻辑:
var htmlDocument = new HtmlDocument(); // 新增这一行,关闭ID属性跟踪 htmlDocument.OptionUseIdAttribute = false; htmlDocument.LoadHtml(userContent);
- 你当前的纯文本提取代码可以优化性能,不需要循环遍历子节点拼接字符串,直接调用
DocumentNode.InnerText即可,避免不必要的字符串拼接开销:
return htmlDocument.DocumentNode.InnerText;
内容的提问来源于stack exchange,提问作者Alexandre TRINDADE
相关产品推荐
相关产品推荐

