/*
*author: ahuaxuan(張榮華)
*date: 2010-05-28
*/ 起因
前一段時間和其他系統整合, 另外乙個系統對某個引數有乙個限制,需要將字串中的特殊字元過濾掉, 由於需要過濾的字元是對方定義的, 所以對方直接把他們系統中的過濾的**給我了, **如下:
private string escape(string s)
stringbuilder sb = new stringbuilder(s.length());
for (int i = 0; i < s.length(); i++) ' || c == '~' || c == '*' || c == '?'
|| c == '|' || c == '&' || c == '>' || c == '<') else
} return sb.tostring();
}
拿到**之後, ahuaxuan沒有作過多的思考, 而是直接把這段**貼到自己的**中, 事實證明它執行」良好」.今天重新審視這段**的時候,發現還是有改進的餘地.
分析 特徵分析, 上面這段**的主要作用是將字串中出現的固定字元替換成空格, 這些需要替換的字元也是我們常見的字元.
面對這樣乙個需求, 有的程式設計師會想到replace方法,有的程式設計師會想到上面的多次||的方法(但是多次||的問題在於如果你的字元不是需要過濾的字元,那麼程式就一直會執行到最後乙個||,這絕對效能上的浪費阿), 也有的程式設計師會想到hash的方式. 其實我們的最終目的其實就是:
給定乙個字元, 你怎麼判斷這個字元是否在某個常見的字元列表中.
你肯定不想用迭代, 你也肯定不想用if else if, 你可能比較喜歡用hash, 但是注意這裡的」常見字元」這幾個字.
是因為它們在ascii 碼裡所以它們才常見, 還是因為他們常見,所以放到ascii 碼裡呢, 但不管怎麼樣, 事實上它們確實是在ascii碼裡, 也就是說他們之中最大的都不會超過255.
所以這個時候, 我們的方案就浮出水面了, 由於我們只要檢查每個char是否==這些常見的char就行了. 說到這裡, 你是不是又想起了if else if, 這個只是思維的慣性, 如果你再把這些char想像成乙個個數字呢.
本質和方案
於是需求就轉換成了---在個數字段中, 找到某些我們預先定義的需要過濾的數字, 並將起替換成空格,而我們定義的數字都是小於255的.
在這樣乙個需求中, 最快的方式是啥咧, 陣列是不, 比如說我們定義的需要過濾的數字是[2, 5], 我們的數字序列是1 2 3 4 5 10 11 110......
那麼我們只要遍歷這個數字, 然後判斷這個數字在我們的過濾陣列中是否存在. 我們的過濾陣列怎麼組織呢?
filterchars = [0, 0, 1, 0, 0, 1],
然後我們只需要判斷filterchars[k] > 1就知道是個字元是否是需要過濾的字元了(當然這裡要注意陣列越界了).
**如下:
public int dic = new int[256];
private string filterchars = "\\+-!()^:{}~*?|&><";
/*** user: ahuaxuan
* date: 2010-5-28
* time: 13:17:11
*/ public charfilter() }}
public string newescape(string abc)
stringbuilder rs = new stringbuilder(abc.length());
for (int k = 0; k < abc.length(); k++) else
}return rs.tostring();
}
測試報告
下面我們來看看這段**:
相同功能的兩段**, 執行一下測試, 測試方法如下:
/**
* user: ahuaxuan
* date: 2010-5-28
* time: 13:17:11
*/ public static void main(string args)
charfilter pt = new charfilter();
string abc = txt.tostring();
long begin = system.currenttimemillis();
for (int k = 0; k < 10000; k++)
system.out.println("escape : " + (system.currenttimemillis() - begin) + "ms");
begin = system.currenttimemillis();
for (int k = 0; k < 10000; k++)
system.out.println("new escape : " + (system.currenttimemillis() - begin) + "ms");
}}
不到1k的乙個文字, 每種方法呼叫100次, 最終得到的結果是:
ahuaxuan 寫道
------------------------0
escape : 103ms
new escape : 67ms
------------------------1
escape : 60ms
new escape : 42ms
------------------------2
escape : 61ms
new escape : 48ms
------------------------3
escape : 58ms
new escape : 39ms
------------------------4
escape : 56ms
new escape : 39ms
------------------------5
escape : 80ms
new escape : 39ms
------------------------6
escape : 55ms
new escape : 40ms
------------------------7
escape : 55ms
new escape : 38ms
------------------------8
escape : 55ms
new escape : 38ms
------------------------9
escape : 59ms
new escape : 41ms
如果我們把對每個不到1k的文字的過濾呼叫上公升到10000次, 那麼測試結果是:
ahuaxuan 寫道
------------------------0
escape : 627ms
new escape : 433ms
------------------------1
escape : 564ms
new escape : 390ms
------------------------2
escape : 624ms
new escape : 390ms
------------------------3
escape : 561ms
new escape : 385ms
------------------------4
escape : 564ms
new escape : 388ms
------------------------5
escape : 600ms
new escape : 391ms
------------------------6
escape : 559ms
new escape : 382ms
------------------------7
escape : 564ms
new escape : 394ms
------------------------8
escape : 573ms
new escape : 395ms
------------------------9
escape : 566ms
new escape : 406ms
文體大小和過濾次數上公升之後, 優化之後的方法比原先的方法快了近200ms.
總結:效能就像女人的胸, 擠一擠還是有的.
當然如果你覺得文中的手段是太入門級了, 那你可以看看ahuaxuan的這篇文章:
使用dfa實現文字過濾
統一記憶體的效能調優
原文 為了實現統一記憶體的良好效能,必須達到以下目標 為了在不使用統一記憶體的情況下達到盡可能高的效能水平,應用程式必須引導統一記憶體驅動子系統避免上述缺陷。值得注意的是,統一記憶體驅動子系統可以檢測常見的資料訪問模式,並在沒有應用程式參與的情況下自動實現其中一些目標。但是,當資料訪問模式不明顯時,...
一次效能調優的實戰
專案情況 是乙個大型公司的內部辦公系統,該系統有兩個和一般企業應用不太一樣的特點 一是使用者量非常多,人員數達到2w左右,另乙個是採用分級管理的形式,各個分公司資料分開管理。我們的定位 我們是作為業務平台的提供商參與這個專案的,我們提供底層的開發平台,系統整合商在此基礎上進行二次開發。在專案從開發到...
一次效能調優的實戰
專案情況 是乙個大型公司的內部辦公系統,該系統有兩個和一般企業應用不太一樣的特點 一是使用者量非常多,人員數達到2w左右,另乙個是採用分級管理的形式,各個分公司資料分開管理。我們的定位 我們是作為業務平台的提供商參與這個專案的,我們提供底層的開發平台,系統整合商在此基礎上進行二次開發。在專案從開發到...