過濾字元的效能調優 擠一擠還是有的

2021-08-30 16:25:00 字數 4460 閱讀 3722

/*

*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左右,另乙個是採用分級管理的形式,各個分公司資料分開管理。我們的定位 我們是作為業務平台的提供商參與這個專案的,我們提供底層的開發平台,系統整合商在此基礎上進行二次開發。在專案從開發到...