最近在看《 linux 系统编程》书的时候,有提到一个概念,就是 read/write 数据时,数据的大小最好与块大小对齐:比如块大小 1k,那么每次调用 read/write 的数据大小最好是 1k 的整数倍,这样会提高性能
里面提到了一个测试:针对 2m 的数据,每次写 1130 字节会比每次写 1024 字节表现更差,因为 1130 不是 1k 的倍数,即没有与块对齐
这里有个疑问: 每次 read/write 实际上都是针对页缓存操作的,后续由操作系统负责页回写到设备。那用户进程每次写的 batch 更大,不是意味着系统调用会更少,整体开销不是会更少吗?跟块设备进行交互的是块读取和块写入,而这个过程并不是发生在 read/write 的流程里的(不阻塞的意思),而是由内核处理, 那么块对齐的优势是体现在哪个方面?
还是说我哪个点理解有错?
1
Mirana 2020-04-13 00:58:13 +08:00
io 分为 buffer 写和非 buffer 写,由 open 的时候带的参数控制
|
2
May725 2020-04-13 00:59:28 +08:00
我的理解是这样的,
假如要读 5k 数据,块大小 1k,如果按照每次读 1k,只需要读 5 次即可完成,累计从磁盘读出 5k 的数据。 如果每次读 1.5k , 则要读 5/1.5 ,取整要读 4 次,由于是整块读,即 2k 读一次,至少累计从磁盘读出 7k 的数据。 5k < 7k,所以优势就出来了。 当然,这是基于 linux 的 read write 不带缓冲导致的,c 语言的 fread fwrie 这些是带缓冲的。 以上有问题的话,希望大佬指出哈。 |
3
kkk330 2020-04-13 01:47:36 +08:00 via iPhone
前不久也刚看完这本书,应该是第 67 页的内容,我的理解是
1. 在用户空间对齐可以避免内核再进行对齐操作,这也是标准 io 库有缓冲区的原因之一,而且按书中描述“避免内核内其他冗余操作”,暗示应该还有其他操作 2. 在对齐的前提下,写入的 batch 比较大确实会减少系统调用,可以测试一下,但我记得越大效果越不明显 |
4
neoblackcap 2020-04-13 02:25:43 +08:00
是的,是对页操作。但是如果每页都是 512B,然后 1130 完全不对齐的话,那么就是每次需要操作 3 页,页用完了就需要换页,这个换页成本就高了。
|
5
vk42 2020-04-13 03:43:08 +08:00
@May725 Linux 的 read 和 write 是 buffered I/O,除非文件是用 O_DIRECT 打开的
没看过书原文,从你介绍里面感觉书里的观点有点太死板了,实际应用可能有很多情况。不对齐可能有负面影响的例子很多,比如内核要做 padding,另外如果是 overwrite,写不满整页还要内核先把原有内容读出来等等 |
6
pabno OP @May725 这里你可以理解有误,read/write 如果不指定 O_DIRECT 都话,都是带内核缓冲区的,fread/fwrite 是带了用户空间缓冲区
|
8
pabno OP @vk42 书中其实是有说明不指定 O_DIRECT 时,是带用内核缓冲区带。
我的疑问是,用户进程每次其实都是在跟内核缓冲区交互,比如我写入 1.5 页数据时,虽然多出的 0.5 页数据没有对齐,但是在页缓存有预读机制。可能在写这 0.5 页时,他对应的那一页数据已经预读到内核缓冲区中了,这时其实就是内存到内存的复制了,这种场景是否对齐已经不重要了? 另外如果系统页回写足够块,比如我写入 0.5 页数据后,页已经回写且淘汰了,我下次再写 0.5 页时,就要再一次读一页的数据到内核缓冲区并修改数据,然后页回写。这种场景页对齐就能减少开销。 不知道我这理解是否正确 |