2013-02-02 267 views
2

我面臨的情況是,僅僅使用C#遍歷MSHTML元素的速度非常慢。這裏是通過document.all三次迭代的迭代的一個小例子。我們有空白WPF應用程序和WebBrowser控件命名的瀏覽器:HTML遍歷速度很慢

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。但它可以這麼慢嗎?每秒300個項目,3,2 GHz CPU的100%核心負載。上面的代碼的

性能分析: Performance analysis

+0

您是否嘗試過使用HTML敏捷性包呢? – svick

+0

不,因爲這是第三方,我們不需要在項目中'解析'HTML,所以我們需要節點作爲對象。 – Dizzy

+4

我不明白區別。 MSHTML確實解析了HTML和Html Agility Pack確實會爲您提供節點作爲對象。 – svick

回答

0

的性能差的源是被定義爲在MSHTML互操作組件動態對象集合項。

public interface IHTMLElementCollection : IEnumerable 
{ 
    ... 
    [DispId(0)] 
    dynamic item(object name = Type.Missing, object index = Type.Missing); 
    ... 
} 

如果我們重寫那個接口,所以它返回IDispatch對象,那麼滯後將消失。

public interface IHTMLElementCollection : IEnumerable 
{ 
    ... 
    [DispId(0)] 
    [return: MarshalAs(UnmanagedType.IDispatch)] 
    object item(object name = Type.Missing, object index = Type.Missing); 
    ... 
} 

新的輸出:

Items: 246, Time: 00:00:00.0034520 
Items: 246, Time: 00:00:00.0029398 
Items: 246, Time: 00:00:00.0029968