淺談提升C#正則表達式效率

作者: 鐵目誘惑  來源: 博客園  發布時間: 2010-11-28 22:17  閱讀: 7262 次  推薦: 0   原文鏈接   [收藏]  
摘要:說到C#的Regex,談到最多的應該就是RegexOptions.Compiled這個東西,傳說中在匹配速度方面,RegexOptions.Compiled是可以提升匹配速度的,但在啟動速度上,使用了RegexOptions.Compiled情況下,通常會使啟動速度慢許多,據說最多是60倍。

  說到C#的Regex,談到最多的應該就是RegexOptions.Compiled這個東西,傳說中在匹配速度方面,RegexOptions.Compiled是可以提升匹配速度的,但在啟動速度上,使用了RegexOptions.Compiled情況下,通常會使啟動速度慢許多,據說最多是60倍。

  進行一組測試,有測試數據,才有討論依據。

  第一步,帖上測試硬件信息(呵呵,硬件有點爛:()

  第二步,

  a.測試在沒有使用RegexOptions.Compiled項時候的情況,隨意使用一些內容,然后循環一萬次實例化正則表達式對象來匹配這些內容。

代碼
 
protected void Page_Load(object sender, EventArgs e)
{
WebClient webClient
= new WebClient();
string content = webClient.DownloadString("http://www.cnblogs.com/tmyh/archive/2010/09/29/sqlindex_01.html");

Stopwatch watcher
= new Stopwatch();
watcher.Start();


int i = 10000;
while (i > 0)
{
Regex rgx
= new Regex("<div>.+?</div>", RegexOptions.IgnoreCase | RegexOptions.Singleline);
bool b1 = rgx.IsMatch(content);

Regex rgx2
= new Regex("<p>.+?</p>", RegexOptions.IgnoreCase | RegexOptions.Singleline);
bool b2 = rgx2.IsMatch(content);

i
--;
}
Response.Write(
string.Concat("<div>", watcher.Elapsed.TotalSeconds.ToString("f7"), "</div>"));
}

  執行發現,內存使用情況為39,760K。輸出的執行時間為3.7954446秒(刷了幾次,取最快的那次)

  b.測試在使用了RegexOptions.Compiled項時候的情況,隨意使用一些內容,然后循環一萬次實例化正則表達式對象來匹配這些內容。

代碼
 
protected void Page_Load(object sender, EventArgs e)
{
WebClient webClient
= new WebClient();
string content = webClient.DownloadString("http://www.cnblogs.com/tmyh/archive/2010/09/29/sqlindex_01.html");


Stopwatch watcher
= new Stopwatch();
watcher.Start();


int i = 10000;
while (i > 0)
{
Regex rgx
= new Regex("<div>.+?</div>", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
bool b1 = rgx.IsMatch(content);

Regex rgx2
= new Regex("<p>.+?</p>", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
bool b2 = rgx2.IsMatch(content);

i
--;
}
Response.Write(
string.Concat("<div>", watcher.Elapsed.TotalSeconds.ToString("f7"), "</div>"));
}

  執行發現,內存使用情況為42,956K。輸出的執行時間為43.3090937秒(刷了幾次,取最快的那次)

  從a和b的測試中發現,不妥當地使用此選項,效率是極其低下的,尤其如果在WEB程序上,如果這個頁面有大流量請求的話,那會有點不堪設想。我們在正常使用中,極大量文本處理的情況似乎比較少出現,基本上不能體現出RegexOptions.Compiled的所在匹配速度優勢,所以通常建議不使用此項。(當然,在正常情況下,我們也不會在每個循環中都new一個正則表達式對象,我們可能會選擇static一個)

  第三步,使用傳說中的Regex.CompileToAssembly來編譯正則表達式,再進行測試。這個,得自己寫個編譯小程序,帖上本人自己寫的一個。點擊下載

  與第二步相同的正則表達式Pattern,用這個工具生成dll后,引用到項目。測試執行,發現執行的內存使用情況與第二步的a差不多,速度也相差不多。當然,在這里,這種測試方案,可能看不出這種預編譯的正則表達式的效率優點,事實上,它應該能夠有更高的執行效率與匹配速度,最好使用多線程與多請求來進行測試。

  在此將其封裝到DLL中,這將使最終的程序占用的內存更少,而不必裝載使用RegexOptions.Compiled編譯正則表達式的包,裝載的速度也就得到了提升,同時也擁有了RegexOptions.Compiled的匹配速度優勢。另外,也提高了需要一直復用的正則表達式的復用率。缺點,就是比較麻煩,而且只有固定的正則表達式能夠這樣使用。(關于如何使用Regex.CompileToAssembly,似乎也沒多少能夠解說的,就三兩行代碼,下載便知)

  似乎并無深入談到原理,不過,也并不重要,我們只要經過測試,知道怎么使用能夠更好就行了。在此,個人的建議是,通常都不要使用RegexOptions.Compiled,即使要在代碼中使用,也應該使用static變量。

  如果真有那么大文本要用的時候,我相信,這個正則表達式也不可能是動態的,固定的正則,我們就使用Regex.CompileToAssembly來先編譯成DLL再引用到項目中,即能提供效率,也提高了復用率。

0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()