Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在一个大文件(C+;+;)上执行许多小的盲写操作的最快方法是什么?_C++_Performance_File Io - Fatal编程技术网

C++ 在一个大文件(C+;+;)上执行许多小的盲写操作的最快方法是什么?

C++ 在一个大文件(C+;+;)上执行许多小的盲写操作的最快方法是什么?,c++,performance,file-io,C++,Performance,File Io,我有一些非常大(>4GB)的文件,其中包含(数百万)固定长度的二进制记录。我希望通过将指针(即64位记录编号)以特定偏移量写入其他文件中的记录,从而(高效地)将它们连接到其他文件中的记录 为了详细说明,我有一对(key,record number)元组列表,对于我想要对给定的一对文件(比如a和B)执行的每个连接,这些元组按key排序。迭代列表对并匹配键,会生成一个(key,record number a,record number B)元组列表,表示连接的记录(为简单起见,假设为1:1映射)。为

我有一些非常大(>4GB)的文件,其中包含(数百万)固定长度的二进制记录。我希望通过将指针(即64位记录编号)以特定偏移量写入其他文件中的记录,从而(高效地)将它们连接到其他文件中的记录

为了详细说明,我有一对(key,record number)元组列表,对于我想要对给定的一对文件(比如a和B)执行的每个连接,这些元组按key排序。迭代列表对并匹配键,会生成一个(key,record number a,record number B)元组列表,表示连接的记录(为简单起见,假设为1:1映射)。为了完成连接,我在概念上需要查找列表中的每个A记录,并在适当的偏移量处写入相应的B记录编号,反之亦然。我的问题是什么才是最快的方法

由于连接的记录列表是按键排序的,因此关联的记录编号基本上是随机的。假设文件比操作系统磁盘缓存大得多,执行一系列随机查找和写入似乎效率极低。我尝试过将A->B和B->A映射放在一个稀疏数组中,并在内存耗尽时将最密集的条目集群刷新到磁盘,从而对记录编号进行部分排序。这样做的好处是,在更新集群的第一个指针后,可以大大增加为集群缓存适当记录的机会。然而,即使在这一点上,通常还是执行一系列查找和盲写,或者手动读取文件的块,更新适当的指针,然后将块写回来更好吗?虽然前一种方法简单得多,操作系统可以对其进行优化,以尽可能减少扇区读取(因为它知道扇区大小)和拷贝(它可以通过直接读取到正确对齐的缓冲区来避免拷贝),但它似乎会产生极高的系统调用开销

虽然我喜欢一个可移植的解决方案(即使它依赖于广泛使用的库,如Boost),但现代Windows和Linux是唯一必备的,因此我可以使用操作系统特定的API(例如CreateFile提示或分散/聚集I/O)。然而,这可能需要做大量的工作来尝试,所以我想知道是否有人能告诉我这是否值得

我尝试过将A->B和B->A映射放在一个稀疏数组中,并在内存耗尽时将最密集的条目集群刷新到磁盘,从而对记录编号进行部分排序。 这似乎会导致极高的系统调用开销

您可以使用对文件的内存映射访问来避免系统调用开销。在*尼克斯,和

将文件逻辑分割为块,例如32MB。如果需要更改块中的某些内容,请使用mmap()修改数据,如果需要,也可以使用msync()修改munmap(),然后移动到下一个块

那是我第一次尝试的。操作系统会自动读取任何需要读取的内容(在第一次访问数据时),并且它会按照自己喜欢的方式对IO进行排队

重要的是要记住,真正的IO并没有那么快。随机访问的性能限制因素包括(1)每秒可处理的IOs(IOPS)存储数量和(2)磁盘搜索数量。(通常IOPS在数百范围内。通常的寻道延迟为3-5ms。)例如,存储可以读/写50MB/s:一秒钟内一个50MB的连续块。但是,如果您试图修补字节为50MB的文件,那么查找时间只会降低性能。在某种程度上,读更多写更多是可以的,即使只更新几个字节也是可以的

另一个需要注意的限制是操作系统IO操作的最大大小:这取决于存储空间,但大多数操作系统都会拆分大于128K的IO任务。如果该限制与存储器中的类似限制同步,则可以更改该限制

同时也要记住存储。许多人忘记了存储通常是唯一的。我想说的是,除非有多个存储,否则启动线程负载对IO没有帮助。即使是单CPU/内核也能够轻松地使RAID10达到800读取IOPS和400写入IOPS的极限。(但每个存储都有一个专用线程至少在理论上是有意义的。)

希望有帮助。这里的其他人经常提到Boost.Asio,我对此没有经验,但它值得一查


顺便说一句,坦白地说,我很想听到对你问题的其他(更多信息)回答。我已经在船上呆过好几次了,但还没有机会真正开始。欢迎阅读与IO优化相关的书籍/链接等(无论平台如何;)

看起来您可以通过使用数据结构来解决这个问题。您有三个约束条件:

  • 访问时间必须相当快
  • 数据必须保持分类
  • 你在旋转的圆盘上
是专门为解决您正在处理的工作负载而创建的。链接的Wikipedia文章中有几个实现链接

从本质上讲,B+树是一种二叉搜索树,但节点组是以组的形式保持在一起的。这样,B+树一次只加载一个块,而不必四处寻找每个节点。它还保留了一些信息,以便知道在搜索中需要哪个块

编辑:如果需要按多个项目排序,可以执行以下操作:


+--------+-------------+-------------+---------+
| Header | B+Tree by A | B+Tree by B | Records |
+--------+-------------+-------------+---------+
      ||      ^     |     ^    |          ^
      |\------/     |     |    |          |
      \-------------------/    |          |
                    |          |          |
                    \----------+----------/

也就是说,每个键都有单独的B+树,以及一个单独的记录列表,指向这些记录的指针存储在B+树中。

我将省去键以节省空间,只构建(记录编号a,记录编号B),而不是构建(键,记录编号a,记录编号B)列表。我会按A对表或文件进行排序,依次查找每个A记录,写入B编号,然后按B对列表进行排序,依次查找每个B记录,写入A编号

我正在做非常类似的大文件操作,这些较新的机器