C語言基本功教程系列 檔案, Socket 和 其它

來源:互聯網
上載者:User
檔案和Socket比較類似,都是在說IO訪問,不過在作業系統層級上的實現有很大不同。 IO訪問無論從什麼角度講,都是電腦系統裡最慢的操作。特別是在遊戲製作中,動不動就幾百兆的動態或者待用資料,貼圖紋理,和各種音響音樂等。要一次性把這些所有的資料讀到記憶體中是不大可能的,所以在遊戲進行過程中要不短的從硬碟或者光碟機裡讀檔案。 如何能夠最小化這個瓶頸, 是值得注意的問題。先從檔案說起吧。

===================檔案==================
C語言裡,正常的檔案操作一般是3步。
fp = fopen(XXXX,XXX);
讀寫操作....
fclose(fp);

首先要注意的是,fopen裡邊要用binary mode開啟檔案,不要用ASCII mode. 很多人在處理文本類型的檔案時候,喜歡用 ASCII mode,然後用fgets一行一行的讀。實際上ASCII mode無論如何操作,都是非常慢的,而且fgets函數更加的慢 [1]。所以即使是文字檔,也要用binary mode開啟,一次讀入一大塊近來,慢慢處理。

其次需要注意的是,每一次讀取檔案的時候,硬碟都會對磁頭進行重新置放和定址。 這點會根據作業系統的不同而不同,總的來說windows XP要比 windows2000好點,但是也只是在系統檔案方面 [2]。 因此每次讀取的內容越多,平均效率就越高。同時作業系統提供磁碟緩衝,當你寫如磁碟的時候,只要不用fflush和fclose,資料在短時間內還是在記憶體中的,如果這時候再讀出來寫如的內容,也非常快。讀寫檔案的時候不要用C++的流。寫檔案一次最好寫不小於4k的資料, 而且最好對檔案結構有效安排,進行連續的訪問(不要頻繁使用fseek)[3]. 這些都有助於提高檔案的訪問速度。

最後,如上文中提到的,每次使用 fclose和fflush的時候,都會強迫檔案從緩衝中寫如到磁碟裡。這個過程極其緩慢而且耗費時間,所以不在必要的時候,不要使用fclose和 fflush. 如果一個檔案讀寫完畢,而你又不確定是否短時間內會用到它,那就不要用fclose.你可以專門寫一個類,管理這寫檔案的指標。對於經常會進行操作的檔案,比如大地圖的texture檔案等,fopen一次就ok了,直到遊戲結束再fclose

===================SOCKET==================
SOCKET雖然也是IO訪問,要比檔案快多了。但是在recv的時候,還是一次讀的越多越好。這樣效率更高。下面說一些SOCKET編程的技巧。

1.  使用非同步socket (asynchronous IO). 在網路程式設計中,又2種處理方式,第一種是對每一個串連請求,都使用一個線程或者進程,第2種是使用一個線程同時使用非同步IO. 第一種方式雖然程式設計上簡單,但是創立進程的時候一般會有一些時間用在建立context上,進程間的轉換和 mutex等也需要浪費很多CPU資源,總體來說不如非同步 IO 有效率 [4]。 

2. 如果必須要使用多線程,可以考慮事先就建立好該線程,然後在需要的時候,把socket發過去就行了[4]。

3. 在處理 UDP協議的時候,需要注意的是,UDP和TCP不一樣。UDP沒有control flow,如果接收端的buffer滿掉了,再來的UDP包都會被drop掉。所以在處理UDP協議的時候,一般需要專門一個線程讀UDP包,防止過多的資料包丟失。

4.  最後,網路資料包多大合適? 這個很難說。對於UDP來說,小包是不划算的. 我們通常用的Ethernet(也就是LAN),在第2層 Data link layer,最大的frame size 是1500 bytes,刨除最20 Bytes(最少)的IP頭,8 bytes的 UDP頭,所有最大的UDP包可以包含 1472個bytes。要是考慮IP包有可能會有附加頭資訊,一般1400就比較合適。但是如果有些老版本 router不地道,對你的UDP包分區的話,就比較慘了。能保證不分區的UDP包大小是513個byte左右 [5],不過畢竟現在這種老的 Router很少了,1400位元組大小的UDP包還是比較安全的。對於TCP來說,因為是stream protocol,不用考慮包的大小。但是TCP 有個缺點,就是如果你一次發送很多很多資料,那麼TCP的速度會一會快,一會慢(見[4]中的關於video streaming的介紹)。所以,需要程式調節,勻速發送資料。

====================其他===================
其他一些程式設計上的東西,很多可以參見 [6]

1. 能用UINT的地方就用UINT,因為很多是UINT最快,而且UINT的除法要比int快。
2. 盡量避免類型轉換,如果最後要轉成float,開始的時候就用float比較好。
3. 不要用double
4. 能用乘法就不要用除法。 比如   3/2 可以換成  3 * 0.5
5. struct的大小盡量是2的倍數,如果不是就調整下,加pad。因為可以在level1 cache裡放整數個。
6. 全域變數少用,如果要用,加上static
7. 局部變數也是越少越少。這樣register的效率更高
8. 能用switch的地方,就不要用if,因為switch是直接產生跳轉表,速度快很多
9. 互相關聯的代碼之間不要空行,功能不同的代碼之間最好空上1行區分開
10. 用const static 代替 #define 定義常量
11. 統一你的代碼風格,始終使用同樣的命名規則

===================最後==================
產生高效率代碼永遠是從使用更好更合適的演算法開始,但是編譯的時候不要忘記開啟你的最佳化開關。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.