【发布时间】:2018-12-20 07:07:42
【问题描述】:
我遇到过使用 C# 简单地遍历 MSHTML 元素的速度非常慢。这是通过 document.all 集合迭代三次的小例子。我们有空白的 WPF 应用程序和名为 Browser 的 WebBrowser 控件:
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Browser.LoadCompleted += DocumentLoaded;
Browser.Navigate("http://google.com");
}
private IHTMLElementCollection _items;
private void DocumentLoaded(object sender, NavigationEventArgs e)
{
var dc = (HTMLDocument)Browser.Document;
_items = dc.all;
Test();
Test();
Test();
}
private void Test()
{
var sw = new Stopwatch();
sw.Start();
int i;
for (i = 0; i < _items.length; i++)
{
_items.item(i);
}
sw.Stop();
Debug.WriteLine("Items: {0}, Time: {1}", i, sw.Elapsed);
}
}
输出是:
Items: 274, Time: 00:00:01.0573245
Items: 274, Time: 00:00:00.0011637
Items: 274, Time: 00:00:00.0006619
1 和 2 行之间的性能差异是可怕的。我尝试用非托管 C++ 和 COM 重写相同的代码,并且完全没有性能问题,非托管代码的运行速度快了 1200 倍。不幸的是,非托管不是一种选择,因为真正的项目比简单的迭代更复杂。
我了解到,运行时第一次为每个引用的 HTML 元素(即 COM 对象)创建 RCW。但它会那么慢吗?在 3.2 GHz CPU 的 100% 核心负载下每秒处理 300 个项目。
上面代码的性能分析:
【问题讨论】:
-
您是否尝试过使用 Html Agility Pack 代替?
-
不,因为这是第 3 方,我们不需要在项目中“解析”HTML,我们需要节点作为对象。
-
我不明白其中的区别。 MSHTML 确实解析 HTML,而 Html Agility Pack 确实为您提供了节点作为对象。
标签: c# performance traversal mshtml