本文講述在編寫(xiě)C程序代碼的常用優(yōu)化辦法,分為I/O篇,內(nèi)存篇,算法篇,MMX匯編篇。
一.I/O篇
如果有文件讀寫(xiě)的話(huà),那么對(duì)文件的訪問(wèn)將是影響程序運(yùn)行速度的一大因素。提高文件訪問(wèn)速度的主要辦法有兩個(gè):一是采用內(nèi)存映射文件,二是使用內(nèi)存緩沖。下面是一組測(cè)試數(shù)據(jù)(見(jiàn)《UNIX環(huán)境高級(jí)編程》3.9節(jié)),顯示了用18種不同的緩存長(zhǎng)度,讀1 468 802字節(jié)文件所得到的結(jié)果。
緩沖大小 | 用戶(hù)CPU(秒) | 系統(tǒng)CPU(秒) | 時(shí)鐘時(shí)間(秒) | 循環(huán)次數(shù)(秒) |
1 | 23.8 | 397.9 | 423.4 | 1 468 802 |
2 | 12.3 | 202.0 | 215.2 | 734 401 |
4 | 6.1 | 100.6 | 107.2 | 367 201 |
8 | 3.0 | 50.7 | 54.0 | 183 601 |
16 | 1.5 | 25.3 | 27.0 | 91 801 |
32 | 0.7 | 12.8 | 13.7 | 45 901 |
64 | 0.3 | 6.6 | 7.0 | 22 951 |
128 | 0.2 | 3.3 | 3.6 | 11 476 |
256 | 0.1 | 1.8 | 1.9 | 5 738 |
512 | 0.0 | 1.0 | 1.1 | 2 869 |
1 024 | 0.0 | 0.6 | 0.6 | 1 435 |
2 048 | 0.0 | 0.4 | 0.4 | 718 |
4 096 | 0.0 | 0.4 | 0.4 | 359 |
8 192 | 0.0 | 0.3 | 0.3 | 180 |
16 384 | 0.0 | 0.3 | 0.3 | 90 |
32 768 | 0.0 | 0.3 | 0.3 | 45 |
65 536 | 0.0 | 0.3 | 0.3 | 23 |
131 072 | 0.0 | 0.3 | 0.3 | 12 |
可見(jiàn),一般的當(dāng)內(nèi)存緩沖區(qū)大小為8192的時(shí)候,性能就已經(jīng)是最佳的了,這也就是為什么在H.263等圖像編碼程序中,緩沖區(qū)大小為8192的原因(有的時(shí)候也取2048大小)。使用內(nèi)存緩沖區(qū)方法的好處主要是便于移植,占用內(nèi)存少,便于硬件實(shí)現(xiàn)等。下面是讀取文件的C偽碼:
int Len;
BYTE buffer[8192];
ASSERT(buffer==NULL);
If buffer is empty{
Len=read(File,buffer,8192);
If(len==0) No data and exit;
}
但是如果內(nèi)存比較大的時(shí)候,采用內(nèi)存映射文件可以達(dá)到更佳性能,并且編程實(shí)現(xiàn)簡(jiǎn)單。內(nèi)存映射的具體使用說(shuō)明見(jiàn)msdn October 2001中的Platform SDK
Documentation—Base Services—File Storage—File Mapping。下面是一點(diǎn)建議:
① 內(nèi)存映射文件不能超過(guò)虛擬內(nèi)存的大小,最好也不要太大,如果內(nèi)存映射文件接近虛擬內(nèi)存大小的時(shí)候,反而會(huì)大大降低程序的速度(其實(shí)是因?yàn)樘摂M內(nèi)存不足導(dǎo)致系統(tǒng)運(yùn)行效率降低),這個(gè)時(shí)候,可以考慮分塊映射,但是我覺(jué)得如果這樣,還不如直接使用內(nèi)存緩沖來(lái)得直接一些。
② 可以將兩種方法統(tǒng)一使用,如我在編大圖像文件數(shù)據(jù)處理的時(shí)候(因?yàn)槭?span lang="EN-US">Unix工作站,內(nèi)存很大GB單位)使用了內(nèi)存映射文件,但是為了最佳性能,也使用了一行圖像緩存,這樣在讀取文件中數(shù)據(jù)的時(shí)候,就保證了僅僅是順序讀寫(xiě)(內(nèi)存映射文件中,對(duì)順序讀寫(xiě)有專(zhuān)門(mén)的優(yōu)化)。
③ 在寫(xiě)文件的時(shí)候使用內(nèi)存映射文件要有一點(diǎn)小技巧:應(yīng)該先創(chuàng)建足夠大的文件,然后將這個(gè)文件映射,在處理完這個(gè)文件的時(shí)候,用函數(shù)SetFilePointer和SetEndOfFile來(lái)對(duì)文件進(jìn)行截尾。
④ 對(duì)內(nèi)存映射文件進(jìn)行操作與對(duì)內(nèi)存進(jìn)行操作類(lèi)似(使用起來(lái)就象數(shù)組一樣),那么如果有大塊數(shù)據(jù)讀寫(xiě)的時(shí)候,切記使用memcpy()函數(shù)(或者CopyMemory()函數(shù))
總之,如果要使用內(nèi)存映射文件,必須:1.處理的文件比較的小,2.處理的文件很大,但是運(yùn)行環(huán)境內(nèi)存也很大,并且一般在運(yùn)行該程序的時(shí)候不運(yùn)行其他消耗內(nèi)存大的程序,同時(shí)用戶(hù)對(duì)速度有特別的要求,而且對(duì)內(nèi)存占用沒(méi)有什么要求。如果以上兩個(gè)條件不滿(mǎn)足的時(shí)候,建議使用內(nèi)存緩沖區(qū)的辦法。