gpt4 book ai didi

c - 磁盘 I/O 期间幕后发生了什么?

转载 作者:太空狗 更新时间:2023-10-29 16:31:14 26 4
gpt4 key购买 nike

当我查找文件中的某个位置并写入少量数据(20 字节)时,幕后发生了什么?

我的理解

据我所知,可以从磁盘写入或读取的最小数据单位是一个扇区(传统上是 512 字节,但该标准现在正在改变)。这意味着要写入 20 个字节,我需要读取整个扇区,修改内存中的部分内容并将其写回磁盘。

这是我期望在无缓冲 I/O 中发生的情况。我也希望缓冲 I/O 做大致相同的事情,但要聪明地使用它的缓存。所以我想,如果我通过随机查找和写入来消除局部性,缓冲和无缓冲 I/O 应该具有相似的性能……也许无缓冲的表现稍好一些。

话又说回来,我知道缓冲 I/O 只缓冲一个扇区是很疯狂的,所以我可能还希望它的性能非常糟糕。

我的申请

我正在存储由 SCADA 设备驱动程序收集的值,该设备驱动程序接收超过十万个点的远程遥测数据。文件中有额外的数据,每条记录为 40 字节,但在更新期间只需要写入其中的 20 字节。

实现前基准

为了检查我是否不需要想出一些出色的过度设计的解决方案,我运行了一个测试,使用几百万条随机记录写入一个文件,该文件可能包含总共 200,000 条记录。为了公平起见,每个测试都使用相同的值为随机数生成器播种。首先,我删除文件并将其填充到总长度(大约 7.6 兆字节),然后循环几百万次,将随机文件偏移量和一些数据传递给两个测试函数之一:

void WriteOldSchool( void *context, long offset, Data *data )
{
int fd = (int)context;
lseek( fd, offset, SEEK_SET );
write( fd, (void*)data, sizeof(Data) );
}

void WriteStandard( void *context, long offset, Data *data )
{
FILE *fp = (FILE*)context;
fseek( fp, offset, SEEK_SET );
fwrite( (void*)data, sizeof(Data), 1, fp );
fflush(fp);
}

也许没有惊喜?

OldSchool 方法名列前茅 - 很多。它快了 6 倍多(每秒 148 万条记录对 232000 条记录)。为了确保我没有遇到硬件缓存,我将数据库大小扩展到 2000 万条记录(文件大小为 763 兆字节)并得到了相同的结果。

在您指出对 fflush 的明显调用之前,我要说删除它没有任何效果。我想这是因为当我在足够远的地方寻找时必须提交缓存,这是我大部分时间都在做的事情。

那么,这是怎么回事?

在我看来,每当我尝试写入时,缓冲 I/O 必须正在读取(并且可能写入所有)文件的一大块。因为我几乎没有利用它的缓存,所以这是非常浪费的。

此外(我不知道磁盘上硬件缓存的细节),如果缓冲 I/O 试图写入一堆扇区而我只更改一个扇区,那会降低硬件缓存的效率.

是否有任何磁盘专家可以比我的实验结果更好地评论和解释这一点? =)

最佳答案

的确,至少在我使用 GNU libc 的系统上,stdio 似乎在写回更改的部分之前正在读取 4kB block 。对我来说似乎是假的,但我想当时有人认为这是个好主意。

我通过编写一个简单的 C 程序来检查打开一个文件,一次写入少量数据,然后退出;然后在 strace 下运行它,看看它实际触发了哪些系统调用。在 10000 的偏移处写入,我看到了这些系统调用:

lseek(3, 8192, SEEK_SET)                = 8192
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1808) = 1808
write(3, "hello", 5) = 5

看来你会想为这个项目坚持使用低级 Unix 风格的 I/O,是吧?

关于c - 磁盘 I/O 期间幕后发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13171052/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com