跳轉到內容

最佳化 C++/通用最佳化技術/輸入/輸出

來自華夏公益教科書,開放的書籍,開放的世界

以壓縮格式儲存文字檔案

[編輯 | 編輯原始碼]

磁碟的頻寬遠低於處理器。透過即時(解)壓縮,CPU 可以加速 I/O。

文字檔案往往可以很好地壓縮。不過,要確保選擇一個快速的壓縮庫;zlib/gzip 非常快,而 bzip2 速度較慢。Boost Iostreams 庫包含 Gzip 過濾器,這些過濾器可用於像讀取普通檔案一樣讀取壓縮檔案。

namespace io = boost::iostreams;

class GzipInput : public io::filtering_istream {
    io::gzip_decompressor gzip;
    std::ifstream file;

  public:
    GzipInput(const char *path)
      : file(path, std::ios_base::in | std::ios_base::binary)
    {
        push(gzip);
        push(file);
    }
};

即使這比“原始”I/O 速度更快(例如,如果你有一個快速的固態硬碟),它仍然可以節省磁碟空間。

通常,以壓縮文字檔案格式儲存的資料比以二進位制格式表示的相同資料在磁碟上佔用的空間更少,即使在二進位制資料被壓縮後也是如此。[1]

二進位制格式

[編輯 | 編輯原始碼]

不要以文字模式儲存資料,而是以二進位制格式儲存。

平均而言,二進位制數字佔用的空間小於格式化數字,因此從記憶體到磁碟或從磁碟到記憶體的傳輸速度更快。此外,如果資料以處理器使用的相同格式傳輸,則無需進行代價高昂的從文字格式到二進位制格式的轉換,反之亦然。

使用二進位制格式的一些缺點是資料不是人可讀的,並且格式可能依賴於處理器架構。

開啟檔案

[編輯 | 編輯原始碼]

不要在每次訪問時都開啟和關閉一個經常需要用到的檔案,而是在第一次訪問時開啟它,並在使用完它後關閉它。

關閉和重新開啟磁碟檔案需要時間。因此,如果你需要經常訪問一個檔案,可以透過在訪問它之前只打開一次檔案,將它的控制代碼包裝器提升到外部作用域,並在完成後關閉它來避免這種開銷。

I/O 緩衝區

[編輯 | 編輯原始碼]

不要對單個小物件或微型物件執行許多 I/O 操作,而是在包含許多物件的 4 KB 緩衝區上執行 I/O 操作。

即使執行時支援的 I/O 操作被緩衝,許多 I/O 函式的開銷也比將物件複製到緩衝區要昂貴。

較大的緩衝區沒有良好的區域性性參考。

記憶體對映檔案

[編輯 | 編輯原始碼]

除了即時系統的關鍵部分,如果你需要以非順序方式訪問二進位制檔案的大部分內容,而不是使用 _seek_ 操作重複訪問它,或者將它全部載入到應用程式緩衝區中,請使用 記憶體對映檔案,前提是你的作業系統提供了此功能。

當你必須以非順序方式訪問二進位制檔案的大部分內容時,有兩種標準的替代技術

  • 在不讀取檔案內容的情況下開啟檔案;並且每當需要資料時,使用檔案定位操作(也稱為 _seek_)跳轉到資料位置,並從檔案中讀取該資料。
  • 分配一個與整個檔案一樣大的緩衝區,開啟檔案,將它的內容讀取到緩衝區中,關閉檔案;並且每當需要資料時,在緩衝區中搜索它。

使用記憶體對映檔案,相對於第一種技術,每個定位操作都用一個簡單的指標賦值操作替換,每個讀取操作都用一個簡單的記憶體到記憶體的複製操作替換。即使假設資料已經存在於磁碟快取中,記憶體對映檔案操作也比相應的檔案操作快得多,因為後者需要許多系統呼叫。

相對於將整個檔案預載入到緩衝區中的技術,使用記憶體對映檔案具有以下優點

  • 當使用檔案讀取系統呼叫時,資料通常首先被傳輸到磁碟快取中,然後傳輸到程序記憶體中,而使用記憶體對映檔案時,可以直接訪問包含從磁碟載入的資料的系統緩衝區,從而節省了複製操作和磁碟快取空間。輸出操作的情況類似。
  • 當讀取整個檔案時,程式會被阻塞相當長的時間,而使用記憶體對映檔案時,這種時間會分散到整個處理過程中,只要訪問檔案就會一直存在。
  • 如果一些會話只需要一小部分檔案,則記憶體對映檔案只加載這些部分。
  • 如果多個程序必須將同一個檔案載入到記憶體中,則每個程序都會為它分配記憶體空間,而使用記憶體對映檔案時,作業系統會將資料的單個副本儲存在記憶體中,供所有程序共享。
  • 當記憶體不足時,作業系統必須將緩衝區中即使尚未更改的部分寫入交換磁碟區域,而記憶體對映檔案的未更改頁面只會丟棄。

但是,在即時系統的關鍵部分,不適合使用記憶體對映檔案,因為訪問資料的延遲取決於資料是否已經被載入到系統記憶體中,或者是否仍然只在磁碟上。

C++ 標準沒有定義記憶體對映介面,實際上 C 介面因平臺而異。Boost Iostreams 庫透過提供 可移植的 RAII 風格介面 來彌補各種作業系統實現之間的差距。類似的、更精簡的開源庫是 cpp-mmf

  1. C2: PowerOfPlainText.
華夏公益教科書