摘要:一段大腸包小腸的程式勾起過去效能問題的回憶
最近看到一段程式碼,寫法是大腸包小腸的For迴圈寫法,意思就是一個For迴圈內又包一個For迴圈,而這段程式主要是在比對大迴圈的值,是否存在於小迴圈內或是那個位置.
ex :
for (int i = 0 ; i<strArrayA.Length ; i++)
{
for (int z = 0 ; z<strArrayB.Length ; z++)
{
if (strArrayA[i].Equal(strArrayB[z]))
{
do something.....
break;
}
}
}
之所以會勾起過去的效能問題,主要是過去有遇到一段難以忘記的效能問題寫法,跟這個做法有點相似,但這寫法在資料量少時,感覺不太出來,但資料量一多加上硬體設備沒那麼好時,整個效能問題的感覺會更加明顯,不過之前遇到的問題寫法有點不同,它是在大的For迴圈內,用一個DataView的RowFilter在過濾資料.用意也是一樣,從大迴圈的值,看是否存在於DataView內.
ex :
foreach (string stra in strArry)
{
DataView1.RowFilter="UserKey ='" + stra + "'";
if (DataView1.Count>0)
{
.....do something.
}
}
看起來似乎沒有什麼問題,而當初在寫這段程式時,預計這作業的功能運用,stra最多不到百筆,DataView也是一樣,但事與願違,事後使用者將其"發揚光大",資料量多達萬筆,這時就明顯的感覺到效能的差異,尤其一般end user的電腦設備沒有我們的好(有些使用者的電腦只有256MB的Ram...),所以他們的感覺更深刻,所以我被罵到臭頭(雖然這段也不是我寫,但這後來由我接手),但前一手會這麼寫也是正常的,如果是我,可能也是會這麼寫,所謂不經一事,不長一智,著手去測試觀察時,發現程式在跑這段時,記憶體會狂升,所以end user記憶體不大的情況下,就會跑page file,效能就更差了,就有位使用者反應,中午先點下去跑,中午吃完飯,睡個午覺,下午就可以用了.聽起來很誇張,但實際還真是如此,因為又加上網路頻寬的不足(2m/256K,8人共用),說真的,沒有發生這件事,還真的不知道RowFilter在這情況下,會有這樣的結果.
後來改了寫法,不用RowFilter,記憶體就沒升的那麼誇張,效能忘了有沒有差到10倍以上,但可以確定的是差很多.而第一個例子的大腸包小腸的兩個for迴圈寫法,是這次看到的,其實我不是很喜歡這種寫法,如果要這麼做,就要考慮到迴圈的次數等問題,雖然例子內有用到break,減少了迴圈次數,但仍覺得不好,這時想到的是Array.IndexOf的做法來取待小迴圈.
ex :
int tmpIndex=0;
for (int i = 0 ; i<strArrayA.Length ; i++)
{
tmpIndex = Array.IndexOf(strArrayB,strArrayA[i])
if (tmpIndex >-1)
{
do something.....
}
}
程式碼看起來變少,但因為DataView的RowFilter經驗,不知道這樣的效能會不會變的更差,於是寫了一個Unit Test比較兩種寫法的效能差異,結果用Array的方式還不錯,效能比用大小腸的好,沒有RowFilter的問題發生,但要感覺出兩種的差別,也是要資料量大及設備差才明顯,不然也是根本就感覺不出來.
很多在Coding的時候,有些地方根本不會想到資料量大後的影響性,比如說在寫一個TreeView的功能,當初設定的的node並不多,最多也不過百筆,但後來使用者的應用方法超出當初設計時的規劃,node超過萬筆,這就可怕了,不只耗效能,使用者也很難從這TreeView中找到所要的資訊,這時所challenge的還有UI操作的便利性,系統的效能下降,使用者操作的效能也變差.
效能的改善是一段無止盡的路~