write(2)最佳的缓冲大小

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了write(2)最佳的缓冲大小相关的知识,希望对你有一定的参考价值。

参考技术A 原文: Optimal buffer size for write(2)

前说一下,我想要写1GB的数据到文件中,在Linux ext3文件系统中使用 write(2)系统调用,发生了非常繁忙的环境(许多IO操作)。在这期间最佳的缓冲大小是多少呢,比如说,4kb,4Mb,什么时候:

1.不使用 O_DIRECT打开标识,或者

2.使用 O_DIRECT

请不要使用“取决于你自己”这样的答案----我想得到一些答案从文件系统的使用者中。

正如评论中讨论的那样,我相信精确的大小不是很重要,比如说:

1.文件系统大小的一小块

2.2的幂(因此系统和内核喜欢它)

3.不太大(适合处理器的一些缓存,比如L2缓存)

4.内存对齐(例如page大小使用posix_memalign)

所以,在 16kbytes到几M字节之间的2的幂的数都应该是可以的。大部分的时间应该是花费了在读磁盘上。文件系统和硬盘的基准应该差不多。

4kbytes通常是page和硬盘chunk的大小。

当然,你可以调整这些事情,在你使用 mke2fs制作文件系统的时候。

我敢打赌最佳的情况取决于你的硬盘(SSD还是普通硬盘)和你的系统(负载)。

根据我的经验回答,更多取决于底层设备和硬件而不是文件系统本身--即设备上的缓存,以及设备写入小块的能力。然而,你不应该写入比你文件系统块更小的数据(stat(.),一般是4kb)--同样,你不应该超出CPU L2、L3缓存大小,在大多数情况下,大小可能低到512kb。

SSD设备一般使用64kb作为操作单元,因此我建议缓冲的大小在 64kb~128kb应该是最优的--这样是我的经验值。

包含stdio.h头文件,应该将BUFSIZ定义为系统的最佳大小。 这绝不是保证,但如果你无法执行广泛的基准测试,这是正确的值,或者这是一个进行基准测试的一个起始值。

管道的原子性 linux写操作原子性

从本质上说,管道也是一种文件,但他又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题

限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中该换冲区的大小为一页,4k

使得他的大小不像文件那样不加检验的增长。使用固定缓冲区也会带来问题,比如再写管道时可能变满

当这种情况发生时,随后对管道的write()调用被阻塞,等待某些数据被读取,以便腾出足够的空间供

write()调用。

读取工作也可能比写的进程快。当所有进程的数据被读取完时,一个随后的read()调用将默认的被阻塞、

管道变空。这种情况发生时,一个随后的read()调用将被默认的阻塞,等待某些数据被写入,这样就解决了read()

调用将被默认的阻塞,等待某些数据将被写入,这解决了read()调用返回文件结束的问题。

一个管道的容量是有限的。POSIX规定,少于 PIPE_BUF 的写操作必须原子完成:要写的数据应被连续的写到管道;大于 PIPE_BUF 的写操作可能是非原子的: 内核可能会把此数据与其它进程的对此管道的写操作交替起来。POSIX规定PIPE_BUF至少为512B(linux中为4096B),具体的语义如下: 其中n为要写的字节数
    n <= PIPE_BUF, O_NONBLOCK无效:原子的写入n个字节。如果管道当前的剩余空间不足以立即写入n个字节,就阻塞直到有足够的空间。
    n <= PIPE_BUF, O_NONBLOCK有效:写入具有原子性,如果有足够的空间写入n个字节,write立即成功返回。否则一个都不写入,返回错误,并设置errno为EAGAIN。
    n >  PIPE_BUF, O_NONBLOCK无效:非原子写。可能会和其它的写进程交替写。write阻塞直到将n个字节写入管道。
    n >  PIPE_BUF, O_NONBLOCK有效:如果管道满,则write失败,返回错误,并将errno设置为 EAGIN。如果不满,则返回写入的字节数为1~n,即部分写入,写入时可能有其他进程穿插写入。

结论:
1、当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
2、当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

以上是关于write(2)最佳的缓冲大小的主要内容,如果未能解决你的问题,请参考以下文章

如何定义通道缓冲区的最佳大小? [关闭]

带有流的文件 I/O - 最佳内存缓冲区大小

TCP缓冲区大小及限制

Android C++系列:Linux文件IO操作

为啥 Linux Open 系统调用不需要路径的缓冲区大小参数?

如何关闭 write() 系统调用的缓冲?