C++二进制文件 I/O 操作速度变慢.数据库如何处理二进制文件?
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,000insert
s通常需要4~5ms,但在特殊情况下需要超过2,000ms。它变得越来越慢,然后需要40~150ms...(x10 ~ x30 慢...我绝对不知道...
- 是什么导致这个特殊的二进制文件 I/O 变慢?
seekg
&seekp
和其他 I/O 操作是否受文件大小影响?(不过我找不到关于这个问题的任何参考资料...- 键、值存储和数据库如何避免这种 I/O 速度变慢?
- 如何解决这个问题?
数据大小
通常磁盘驱动器块大小是 2 的幂,因此如果数据块大小也是 2 的幂,那么基本上可以消除数据块跨越磁盘块边界的情况。
在您的情况下,64 字节的值(如果您不需要存储哈希,则为 32 字节(可能会表现得更好一些。
广告顺序
您可以做的另一件事来提高性能是增加哈希顺序以减少必须从磁盘加载数据的时间数。
通常,当数据读取或写入磁盘时,操作系统一次会读/写一个大卡盘(可能是 4k(,所以如果你的算法是及时在本地写入数据的一种方式,你将减少数据实际必须读取或写入磁盘的时间。
鉴于您进行了大量插入,一种可能性是一次批量处理插入,例如 1000 个甚至 10000 个键/值对。本质上,您将在内存中积累数据并对其进行排序,一旦您有足够的项目(或完成插入(,您将按顺序写入数据。
这样,您应该能够减少非常慢的磁盘访问。如果您使用传统硬盘驱动器,这可能更为重要,因为移动头部很慢(在这种情况下,对其进行碎片整理可能很有用(。另外,请确保您的硬盘驱动器有足够的可用空间。
在某些情况下,本地缓存(在应用程序中(也可能很有帮助,尤其是在您知道如何使用数据的情况下。
文件大小与
冲突使用哈希时,您希望找到文件大小和冲突之间的最佳平衡点。如果你有太多的碰撞,那么你会浪费很多时间,在某些时候,当几乎每次插入都很难找到一个空闲的地方时,它可能会退化。
另一方面,如果您的文件确实非常大,则最终可能会遇到这样一种情况:您可能会用主要是空的数据填充RAM,并且在几乎所有插入时仍然需要用磁盘中的数据替换数据。
例如,如果您的数据是 20GB,并且您可以在内存中加载 2 GB,那么如果插入确实是随机的,则 90% 的时间您可能需要真正访问硬盘驱动器。
配置
井选项将取决于操作系统,这超出了编程论坛的范围。如果你想优化你的电脑,那么你应该看看其他地方。
读数
阅读操作系统(文件系统,缓存层...(和算法(外部排序算法,B树和其他结构(可能会有所帮助,以便更好地理解。
选择
- 额外的内存
- 快速固态硬盘
- 多线程(例如输入和输出线程(
- 重写算法(例如,一次读取/写入整个磁盘页(
- 更快的中央处理器/64位计算机
- 使用专为此类方案设计的算法。
- 使用数据库。
- 分析代码
- 调整参数
- 正在读取二进制文件(is_open)
- 在C++中将类(带有Vector成员)保存为二进制文件
- 如何从二进制文件中读取字符串
- 保存/加载大量短数组到二进制文件
- 从二进制文件中读取整数数组
- Android 在编译二进制文件时重建静态库
- 在 C++ 中将双精度变量写入二进制文件
- clang 的 libFuzzer 可以在同一二进制文件中测试超过 1 个 API 吗?
- C++二进制文件 I/O 操作速度变慢.数据库如何处理二进制文件?
- 如何使用自定义对象的序列化在 c++ 中编写自定义二进制文件处理程序
- 我有一个预处理的 C/C++ 源文件 (cacti.i).如何从这个 .i 文件生成可执行二进制文件,以便我可以像 ./
- c_str() 或reinterpret_cast更适合处理二进制文件
- 在处理二进制文件时了解 Seekg() 和 seekp()
- 使用字符串流处理二进制文件时出现问题
- 从二进制文件读取后,当控件返回到调用函数时,出现未处理的异常
- 函数调用者如何使用头文件来确定如何处理已编译的二进制文件
- 在使用Rcpp构建包时处理修饰的外部二进制文件
- 从二进制文件输入字符串时未处理的异常| VisualStudio
- 文件处理文本文件或二进制文件
- 显示垃圾值的二进制文件处理程序(Turbo c++)