我想制作一个缓冲区约为 5MB 的 FIFO 管道。我知道 Linux 中默认的 FIFO 管道缓冲区最大值约为 1MB。我看到它位于 /proc/sys/fs/pipe-max-size
我尝试将其设置如下:
sudo sysctl fs.pipe-max-size=4194304
然后我看到值确实被改变了:
$ cat /proc/sys/fs/pipe-max-size
4194304
然后我创建了一个新的 FIFO 管道,但我没有注意到性能有任何改进。它的填满速度似乎与之前的 1MB FIFO 管道相同。所以我不确定我的新 FIFO 管道实际上有 4MB 缓冲区。
我如何 1) 增加系统 FIFO 管道缓冲区最大值和 2) 创建使用此缓冲区最大值的 FIFO 管道?
答案1
您的命令更改最大缓冲区大小,而不是默认缓冲区大小。
来自管道(7) 联机帮助页:
/proc/sys/fs/pipe-max-size
(自 Linux 2.6.35 起)不具有 CAP_SYS_RESOURCE 功能的用户可以设置的单个管道的最大大小(以字节为单位)。
和:
从Linux 2.6.11开始,管道容量为16页(即在页大小为4096字节的系统中为65,536字节)。从Linux 2.6.35开始,默认管道容量为16页,但可以使用
fcntl
(2)F_GETPIPE_SZ
和F_SETPIPE_SZ
操作来查询和设置容量。
因此,除非您fcntl(F_SETPIPE_SZ)
在打开的管道上调用系统调用,否则它将保持默认容量:64 kB。为此,您必须使用一种提供系统调用绑定的语言(C/C++、Python、PHP、perl...但不是 sh/bash)。
答案2
根据 xhienne 的回答,此 perl 脚本将设置现有打开 fifo 的大小:
#!/usr/bin/perl
# usage: name-of-open-fifo size-in-bytes
# http://unix.stackexchange.com/a/353761/119298
use strict;
use Fcntl;
my $fifo = shift @ARGV or die "usage: fifo size";
my $size = shift @ARGV or die "usage: fifo size";
open(FD, $fifo) or die "cannot open";
printf "old size %d\n",fcntl(\*FD, Fcntl::F_GETPIPE_SZ, 0);
my $new = fcntl(\*FD, Fcntl::F_SETPIPE_SZ, int($size));
die "failed" if $new<$size;
printf "new size %d\n",$new;
将其放入一个文件中,例如~/setfifo
,chmod +x
对其执行操作,然后在创建并打开 fifo 后运行它,例如:
$ mkfifo /tmp/fifo
$ cat -n <>/tmp/fifo &
$ ~/setfifo /tmp/fifo 1048576
old size 65536
new size 1048576
如果您的 Perl 还没有常量F_GETPIPE_SZ
和F_SETPIPE_SZ
,您可以使用通过查看 中的 C 文件找到的适当数字/usr/include/
。分别是1024+8和1024+7。这是生成的 perl 脚本:
#!/usr/bin/perl
# usage: name-of-open-fifo size-in-bytes
# http://unix.stackexchange.com/a/353761/119298
use strict;
# int fcntl(int fd, int cmd, ...) F_GETPIPE_SZ,void F_SETPIPE_SZ,int
# /usr/include/asm-generic/fcntl.h #define F_LINUX_SPECIFIC_BASE 1024
# /usr/include/linux/fcntl.h #define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
sub F_SETPIPE_SZ{ 1024+7; }
sub F_GETPIPE_SZ{ 1024+8; }
my $fifo = shift @ARGV or die "usage: fifo size";
my $size = shift @ARGV or die "usage: fifo size";
open(FD, $fifo) or die "cannot open";
printf "old size %d\n",fcntl(\*FD, F_GETPIPE_SZ, 0);
my $new = fcntl(\*FD, F_SETPIPE_SZ, int($size));
die "failed" if $new<$size;
printf "new size %d\n",$new;