IO之標准C庫buffer

在論述這個主題之前,先介紹一下標准C庫和linux系統調用以及windows API之間的關系。

拿寫文件來舉個例子

linux下寫文件用write()

windows下寫文件用WriteFile()

這說明不同操作系統實現同樣的系統功能的接口應該是不一樣的。造成這種現狀是操作系統發展的曆史原因造成的,無法在操作系統的層面統一系統函數接口。同樣功能的程序在linux上寫一套,windows上又得寫另外一套,毫無移植性可言。如果要開發一個既能在linux跑,又能在windows上跑的程序,開發成本飙升!

爲了解決這個移植性的問題,標准C庫利用了封裝技術,扮演了一個重要的角色,統一了部分基本功能接口。

標准C規定的寫文件的函數是fwrite(),就是不管在linux還是在windows上,各自都有一個標准C庫,庫函數封裝的下層細節不一樣,但是接口完全一樣,提供的功能完全一樣。

這是怎麽做到的?猜一猜大致實現就知道了

在linux上,標准C接口fwrite()的實現僞代碼

size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream){

   ...

   ...

   return write(stream->fd,buffer,count);

}

在windows上,標准C接口fwrite()的實現僞代碼

size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream){

#define OUT 

   BOOL ret = false;

   OUT int optnum;

   ...

   ...

    ret = WriteFile(stream->filehandle, buffer, count, &optnum,...);

    if( ret == true)

       return optnum;

   else

       return -1;

}

 

內部實現不一致,沒關系,接口一樣就可以,不管在linux還是windows上,寫文件都用fwrite(),分別在各自平台上編譯就可以了。

標准C就是這樣一個處于系統層面之上的應用層標准函數庫,爲了統一各個操作系統上的函數接口而生。

 

回到我們的主題----IO之應用層buffer

什麽是應用層buffer?

回想一下我之前介紹的《IO之內核buffer"buffer cache"》,既然write()能把需要寫文件的數據推送到一個內核buffer來偷工減料欺騙應用層(爲了加速I/O),說“我已經寫完文件並返回了”。那應用層的標准C庫的fwrite()按道理也可以爲了加速,在真正調用write()之前,把數據放到(FILE*)stream->buffer中,等到多次調用fwrite(),直至(FILE*)stream->buffer中積攢的數據量達到(FILE*)stream->bufferlen這麽多的時候,一次性的把這些數據全部送入write()接口,寫入內核,這是多麽美妙啊。。。

實際上,標准C庫就是這麽做的!

把fwrite()的linux實現再細致一下

過程其實仍然很粗糙,爲了突出buffer的重點,計算stream->buffer是否滿,拷貝多少,填充多少這樣的細節和主題無關的東西我略去了

size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream){

   ...

   if( stream->buffer滿 ){

       write(stream->fd,stream->buffer,stream->bufferlen);

   } else{

       拷貝buffer內容至stream->buffer

   }

   ...

    return count;

   //過程很粗糙,爲了突出buffer的重點,計算stream->buffer是否滿,拷貝多少,填充多少這樣的細節和主題無關的東西我略去了

}

fwrite()在windows平台的實現也基本上是這樣的,也有buffer。

值得一說的是,fread()也有一個讀cache來完成預讀。

 

setvbuf()和setbuf()都是控制這個標准C庫的buffer的。

還有fflush()是C庫用于flush數據的函數。

以上三個函數,如果大家有興趣,可以去看看linux上對應的man文檔。

重點是要知道不僅系統的內核有buffer,應用層的C庫同樣也有buffer。這些buffer的唯一作用就是爲了加速應用,不讓應用老是卡在和磁盤交互上。

說個題外話,實際上對于磁盤、RAID卡、盤陣這樣的外存介質而言,他們各自在硬件上也都有一層前端的buffer,有時也叫cache,用來緩沖讀寫加速。cache越多,價格越貴,效能越好。大型存儲設備一般擁有多層cache,用的是昂貴的SSD。
需要分享的一點經驗是,不管是標准C庫的buffer也好,內核的"buffer cache"也罷,我們終究對它們的控制力度是有限的。我們在做伺服器程序的時候,如果業務上涉及太大的I/O量,需要做服務整體加速的時候,我們一般自己在業務層做一層自己的"buffer",把業務數據buffer住,攢成以文件系統或者磁盤的block塊單位的大塊數據,然後集中寫,然後集中寫又有集中寫的策略。。。
再引申一點內容,做高效能大流量的大站的架構,其中最重要幾個架構角色之一就是cache。前端CDN、後端memcache、redis、mysql內部cache等等,都是cache的應用場景,可以說"buffer cache"在伺服器領域從軟件實現到硬件加速再到架構,真的是無處不在。


更多相關文章
  • C++標准模板庫與數據結構的學習
    STL(Standard Template Library),即標准模板庫,是一個具有工業強度的,高效的C++程序庫.它被容納于C++標准程序庫(C++ Standard Library)中,是ANSI/ISO C++標准中極具革命性的一部分.該庫包含了諸多在計算機科學領域裏所常用的基本數據結構和基 ...
  • #@author: gr #@date: 2014-07-18 #@email: forgerui@gmail.com 下面進行STL的學習.希望能了解標准模板庫中的常用容器,疊代器,可以自由運用STL以提高編寫代碼的效率.下面的內容我想以知識點爲總結,不再像<Effective C++> ...
  • C++強大的功能來源于其豐富的類庫及庫函數資源.C++標准庫的內容總共在50個標准頭文件中定義.在C++開發中,要盡可能地利用標准庫完成.這樣做的直接好處包括:(1)成本:已經作爲標准提供,何苦再花費時間.人力重新開發呢:(2)質量:標准庫的都是經過嚴格測試的,正確性有保證:(3)效率:關于人的效率 ...
  • 一.STL集合類標准模板庫向程序員提供了一些容器類,以便在應用程序中頻繁而快速的搜索.std::set和std::multiset用于存儲一組經過排序的元素,其查找元素的複雜度爲對數,而unordered集合的插入和查找時間是固定的.容器set和multiset快速查找鍵,鍵是存儲在一維容器中的值, ...
  • 參考<21天學通C++>第15和16章節,在對宏和模板學習之後,開啓對C++實現的標准模板類STL進行簡介,同時介紹簡單的string類.雖然前面對于vector.deque.list等進行過學習和總結,但並沒有一個宏觀上的把握,現在通過上一篇和這一篇博文,將對C++模板以及基于C++模 ...
  •  一.STL簡介STL(Standard Template Library,標准模板庫)是惠普實驗室開發的一系列軟件的統稱.它是由Alexander Stepanov.Meng Lee和David R Musser在惠普實驗室工作時所開發出來的.現在雖說它主要出現在C++中,但在被引入C++之前該技 ...
  • 本文討論了如何執行以下任務: 導出實例化的一個標准模板庫 (STL) 類. 導出包含一個 STL 的一個數據成員的類對象. 請注意您可以不導出一個通用的模板.必須進行實例化模板 : 也就是所有模板參數時必須提供,並且必須完全定義的類型的實例化. 實例"堆棧 <int>:&quo ...
  • C++入門學習——標准模板庫之map
    map 是 STL 的一個關聯容器,它提供一對一(其中第一個可以稱爲關鍵字,每個關鍵字只能在 map 中出現一次,第二個可能稱爲該關鍵字的值)的數據處理能力,由于這個特性,它完成有可能在我們處理一對一數據的時候,在編程上提供快速通道.這裏簡單說一下 map 內部數據的組織,map內部自建一顆紅黑樹( ...
一周排行