C++ 将32位整数存储到磁盘的绝对最快方式?

C++ 将32位整数存储到磁盘的绝对最快方式?,c++,c,linux,file-io,low-latency,C++,C,Linux,File Io,Low Latency,我有一个对延迟非常敏感的例程,它按顺序生成整数,但需要将最后生成的整数存储到磁盘,以防崩溃或重新启动 目前,我正在寻找文件的开头,然后写出整数,然后在每次生成新的int时刷新。需要刷新,以便写入操作至少命中备有电池的控制器缓存 查找非常昂贵,因此我考虑只追加4个字节,如果需要恢复,则将查找结束并读取最后4个字节。前面的语句显然假设没有太多其他磁盘活动发生,因此理想情况下,写入头应该留在文件的末尾 这个数字通常不会超过10000000,因此40MB也不是那么糟糕 关于如何在不牺牲完整性的情况下实现

我有一个对延迟非常敏感的例程,它按顺序生成整数,但需要将最后生成的整数存储到磁盘,以防崩溃或重新启动

目前,我正在寻找文件的开头,然后写出整数,然后在每次生成新的int时刷新。需要刷新,以便写入操作至少命中备有电池的控制器缓存

查找非常昂贵,因此我考虑只追加4个字节,如果需要恢复,则将查找结束并读取最后4个字节。前面的语句显然假设没有太多其他磁盘活动发生,因此理想情况下,写入头应该留在文件的末尾

这个数字通常不会超过10000000,因此40MB也不是那么糟糕

关于如何在不牺牲完整性的情况下实现最小延迟,有什么建议吗


Linux上的P>C或C++ 2.6 ++/P>< P>如果我读正确,那么使用内存映射文件如何?只需将您的号码写入指定的地址,它就会出现在文件中。这就假设操作系统在需要时会将缓存写入磁盘,但您可能会发现值得一试

int len = sizeof(unsigned);
int fildes = open(...)
void* address = mmap(0, len, PROT_READ, MAP_PRIVATE, fildes, 0)
unsigned* mappedNumber = (unsigned*)(address);

*mappedNumber现在可以包含整数。

我认为最快/最简单的方法是使用mmap/msync--mmap将文件的1页存储到内存中,并将值存储在该页上。每当值发生变化时,调用msync(2)将页面强制返回到磁盘。这样,每个门店只需一次系统调用

度量。

你对硬件有多少控制权?如果任何东西不够满,你将得不到任何保证

在Linux上,我可能会尝试制作一个内核驱动程序,它可以以最高优先级进行写操作,甚至可能不使用文件系统

但是,理论上。。。如果命中控制器缓存就足够了,那么每次将任何内容刷新到磁盘时,数据都会命中控制器缓存。这意味着,无论驱动器内部是否存在物理寻道,数据都已经存在。而且,因为您永远不知道其他应用程序会做什么,或者磁盘旋转的速度有多快,所以即使您将逻辑文件句柄保留在文件的开头或结尾,您的搜索也将是随机的


您可以随时要求用户使用闪存驱动器。

写入文件的最快方法是将该文件映射到内存中,并将其视为字符数组

如果您不关心操作系统崩溃(Linux在生产中从未在我身上崩溃),则不需要同步文件。您所有的写入都绕过内核进入该文件映射,换句话说,真正的零拷贝(在标准硬件上还不能使用套接字)。您可能需要在该文件中保留一个头文件,其中包含大量写入的记录,以防在将记录写入内存时应用程序崩溃。即,写入一条记录,并且仅在该记录计数器递增之后

调整此文件的大小需要
ftruncate()/remap()
序列,这可能会花费太长的时间,因此您可能希望通过将文件增加一个因子来最小化大小调整,例如
std::vector
在溢出时将其大小在
push_back()
上增加1.5。根据吞吐量和延迟要求,可以应用某些优化


内核将以异步方式将文件映射写入磁盘(就像应用程序中有另一个线程专用于写入磁盘一样)。如果需要,可以使用
msync()
强制写入磁盘。然而,这只是必要的,如果你想在操作系统崩溃中幸存下来。但要想在操作系统崩溃中幸存下来,无论如何都需要复杂的应用程序设计,因此在实践中,在应用程序崩溃中幸存下来已经足够了。

为什么应用程序必须等待写操作完成

异步写入数据,或者从另一个线程写入数据


你实际上对硬盘没有太多的低级控制。只要你一次只写很少的数据,你就会招致很多昂贵的搜索。但由于您仅将其用作“检查点”,以便在发生崩溃时进行恢复,因此似乎没有理由不能异步进行写入。

存储int只需要磁盘上的一个块,而不管块大小如何。所以你必须将一个数据块同步到光盘上,它需要的时间和它需要的时间一样长,而且你也无法让它更快

无论您做什么,fdatasync()都将是时间方面的杀手。它会将一个数据块同步到您的(备有电池的RAID)控制器中

除非您有某种非易失性ram,否则所有(合理的)方法都将是完全等效的,因为它们都需要一个块进行同步

执行seek系统调用不会产生任何影响,因为这对硬件没有影响。在任何情况下,都可以通过使用pwrite()来避免它。

考虑“追加4个字节”的含义。磁盘不存储文件,甚至不存储字节。它们存储集群和固定数量的集群。文件的概念是由操作系统创建的。它将一些集群分配给文件系统表,以跟踪文件的精确位置。现在,追加4个字节意味着至少要将4个字节写入集群。但这也意味着要确定哪个集群。现有的文件大小是多少?我们需要一个新的集群吗?如果没有,我们需要读取最后一个集群,将4个字节修补到正确的位置,然后写回集群,然后更新文件系统中的文件大小。如果我们添加了一个新的集群,我们可以写入4个字节,后跟0(不需要旧值),但是我们需要做大量的簿记来将集群添加到文件中

因此,绝对最快的方法不可能是追加4个字节。您必须覆盖4个现有字节。最好是在内存中已有的扇区中。其他人已经指出,使用
mmap/msync
可以实现这一点

显然,考虑到当前SSD和开发人员的价格