簡體   English   中英

C++ 二進制文件 I/O 操作變慢... DB 如何處理二進制文件?

[英]C++ Binary File I/O Operations Slow Down... How DB Handle Binary Files?

我正在嘗試制作一個簡單的基於文件的哈希表。 這是我的insert成員函數:

private: std::fstream f;  // std::ios::in | std::ios::out | std::ios::binary

public: void insert(const char* this_key, long this_value) {
    char* that_key;
    long that_value;
    long this_hash = std::hash<std::string>{}(this_key) % M;
    long that_hash;  // also block status

    long block = this_hash;
    long offset = block * BLOCK_SIZE;
    while (true) {
        this->f.seekg(offset);
        this->f.read((char*) &that_hash, sizeof(long));
        if (that_hash > -1) {  // -1 (by default) indicates a never allocated block
            this->f.read(that_key, BLOCK_SIZE);
            if (strcmp(this_key, that_key) == 0) {
                this->f.seekp(this->f.tellg());
                this->f.write((char*) &this_value, sizeof(long));
                break;
            } else {
                block = (block + 1) % M;  // linear probing
                offset = block * BLOCK_SIZE;
                continue;
            }
        } else {
            this->f.seekp(offset);
            this->f.write((char*) &this_hash, sizeof(long));  // as block status
            this->f.write(this_key, KEY_SIZE);
            this->f.write((char*) &this_value, sizeof(long));
            break;
        }
    }
}

測試多達 10M 的鍵值對,包含 50,000,017 個塊,結果相當不錯。 (二進制文件大小約為 3.8GB)。

但是,使用 50M 密鑰和 250,000,013 個塊進行的測試非常慢......(在這種情況下,二進制文件大小超過 19GB)。 1,000 insert s通常需要4~5ms,但特別需要2,000ms以上。 它變得越來越慢,然后需要 40~150 毫秒......(x10 ~ x30 慢......)我絕對不知道......

  • 是什么導致這種異常的二進制文件 I/O 變慢?
  • seekg & seekp等 I/O 操作是否受文件大小影響? (雖然我找不到關於這個問題的任何參考資料......)
  • 鍵、值存儲和數據庫如何避免這種 I/O 減慢?
  • 我怎么解決這個問題?

數據大小

通常磁盤驅動器塊大小是 2 的冪,所以如果您的數據塊大小也是 2 的冪,那么您基本上可以消除數據塊跨越磁盤塊邊界的情況。

在您的情況下,64 字節的值(如果您真的不需要存儲散列,則為 32 字節)可能會表現得更好一些。

廣告訂單

你可以做的另一件事是提高性能,你的插入是增加哈希順序,以減少必須從磁盤加載數據的時間。

一般在磁盤讀寫數據時,OS會一次讀寫一個大chuck(可能4k),所以如果你寫的算法是一種及時在本地寫入數據的方式,你會減少次數數據必須實際讀取或寫入磁盤。

鑒於您進行了大量插入,一種可能性是一次批量處理插入,例如 1000 個甚至 10000 個鍵/值對。 本質上,您將在內存中累積數據並對其進行排序,一旦您有足夠的項目(或完成插入),您將按順序寫入數據。

這樣,您應該能夠減少非常緩慢的磁盤訪問。 如果您使用傳統硬盤驅動器,這可能更重要,因為移動磁頭很慢(在這種情況下,對其進行碎片整理可能很有用)。 另外,請確保您的硬盤驅動器有足夠的可用空間。

在某些情況下,本地緩存(在您的應用程序中)也可能會有所幫助,特別是如果您知道如何使用您的數據。

文件大小 VS 沖突

當您使用散列時,您希望找到文件大小和沖突之間的最佳位置。 如果您有太多的碰撞,那么您將浪費大量時間,並且在某些時候它可能會退化,因為幾乎每次插入都很難找到空閑位置。

另一方面,如果您的文件確實非常大,您最終可能會遇到這樣一種情況:您可能會用主要為空的數據填充 RAM,並且在幾乎所有插入時仍需要用磁盤中的數據替換數據。

例如,如果您的數據是 20GB,並且您可以在內存中加載 2GB,那么如果插入真的是隨機的,那么 90% 的時間您可能需要真正訪問硬盤。

配置

好選項將取決於操作系統,它超出了編程論壇的范圍。 如果您想優化您的計算機,那么您應該尋找其他地方。

閱讀有關操作系統(文件系統、緩存層……)和算法(外部排序算法、B 樹和其他結構)以更好地理解可能會有所幫助。

備擇方案

  • 額外的內存
  • 快速固態硬盤
  • 多線程(例如輸入和輸出線程)
  • 算法的重寫(例如一次讀/寫整個磁盤頁面)
  • 更快的 CPU / 64 位計算機
  • 使用為此類場景設計的算法。
  • 使用數據庫。
  • 分析代碼
  • 調整參數

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM