我最近读到了有关命名管道的文章,但我不明白它们为什么存在。
我读到过一些文章说使用命名管道比使用文件更省时。
为什么会这样?
命名管道也必须存储在内存中(可能被交换,就像文件一样)。
据我所知,它们必须获得一个必须由当前目录引用的 inode,就像文件一样。此外,它们必须由程序员删除,就像文件一样。
那么优势在哪里呢?
答案1
Linux 中的几乎所有内容都可以被视为文件,但常规文件和一个命名管道命名管道是文件系统上没有内容的文件的特殊实例。
以下是引自man fifo
:
FIFO 特殊文件(命名管道)与管道类似,不同之处在于它是作为文件系统的一部分进行访问的。它可以由多个进程打开以进行读取或写入。当进程通过 FIFO 交换数据时,内核会在内部传递所有数据,而不会将其写入文件系统。因此,FIFO 特殊文件在文件系统上没有内容;文件系统条目仅用作参考点,以便进程可以使用文件系统中的名称访问管道。
内核为每个由至少一个进程打开的 FIFO 特殊文件维护一个管道对象。在数据传送之前,必须在两端(读取和写入)打开 FIFO。通常,打开 FIFO 会阻塞,直到另一端也打开为止。
因此,实际上命名管道不执行任何操作,除非有进程对其进行读写。它不占用硬盘上的任何空间(除了少量元信息),也不使用 CPU。
您可以通过以下方式检查:
创建命名管道
$ mkfifo /tmp/testpipe
例如,转到某个目录/home/user/Documents
,然后使用命名管道对其中的所有内容进行 gzip 压缩。
$ cd /home/user/Documents
$ tar cvf - . | gzip > /tmp/testpipe &
[1] 28584
在这里您应该看到 gzip 进程的 PID。在我们的示例中,它是 28584。
现在检查一下这个 PID 在做什么
$ ps u -P 28584
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
c0rp 28584 0.0 0.0 29276 7800 pts/8 S 00:08 0:00 bash
您将看到它正在使用没有资源. 0% CPU 使用率,0% 内存使用率。
验证有关文件空间使用情况的猜测
$ du -h /tmp/testpipe
0 testpipe
再次0
,什么也没有。如果需要,可以再次使用测试管。
不要忘记使用 终止 gzip kill -15 28584
。然后使用 删除命名管道rm /tmp/testpipe
示例用法
您可以使用命名管道重定向几乎所有内容。例如,您可以看到一行代理。
还这是另一个很好地解释了命名管道的使用。您可以在一台服务器上配置两个进程,使用命名管道而不是 TCP/IP 堆栈进行通信。这样速度更快,并且不会加载网络资源。例如,您的 Web 服务器可以使用命名管道直接与数据库通信,而不是使用localhost
地址或监听某个端口。
答案2
确实,您不会使用系统内存,但是您在示例中不使用 CPU 只是因为您没有读取管道,所以进程正在等待。
考虑以下例子:
mkfifo /tmp/testpipe
tar cvf - / | gzip > /tmp/testpipe
现在打开一个新的控制台并运行:
watch -n 1 'ps u -P $(pidof tar)
在第三个控制台中:
cat /tmp/testpipe > /dev/null
如果你看一下 watch cmd(第二项),它将显示 CPU 消耗的增加!
答案3
以下是命名管道可以通过删除 I/O 可以节省您大量时间。
假设您有一个BigFile,例如10G。
您还可以将此 BigFile 分割成 1G 大小的块,从 BigFileSplit_01 到 BigFile_Split_10。
现在你对 BigFileSplit_05 的正确性产生了怀疑
天真地,如果没有命名管道,您可以从 BigFile 创建一个新的分割并进行比较:
dd if=BigFile of=BigFileSplitOrig_05 bs=1G skip=4 count=1
diff -s BigFileSplitOrig_05 BigFileSplit_05
rm BigFileSplitOrig_05
使用命名管道,你可以这样做
mkfifo BigFileSplitOrig_05
dd if=BigFile of=BigFileSplitOrig_05 bs=1G skip=4 count=1 &
diff -s BigFileSplitOrig_05 BigFileSplit_05
rm BigFileSplitOrig_05
乍一看,这可能看起来并不是很大的区别...但随着时间的推移,区别就变得巨大了!
选项1:
- dd:读取 1G/写入 1G (1)
- 差异:读取2G
- rm:释放已分配的簇/删除目录条目
选项 2:
- dd:没什么!(进入命名管道)
- 差异:读取2G
- rm:没有分配的集群需要管理(我们实际上没有向文件系统写入任何内容)/删除目录条目
因此基本上命名管道为您节省了 1G 的读写以及一些文件系统清理(因为我们除了空的 fifo 节点之外没有向文件系统写入任何内容)。
不执行 I/O(尤其是写入)也有助于避免磁盘磨损。使用 SSD 时,情况会更加有趣,因为在单元损坏之前,SSD 的写入次数有限。
(1) 显然,另一个选择是将临时文件创建到 RAM,例如,如果 /tmp 已安装到 RAM (tmpfs)。不过,您会受到 RAM 磁盘大小的限制,而“命名管道技巧”则没有限制。
答案4
您可以让程序静止不动,并监听命名管道中的某些外部事件。一旦发生外部事件(例如,一些新数据的到达),其他程序就可以检测到,然后打开管道进行写入,将相关事件数据写入管道。发出 close 语句后,监听程序将通过 read 语句通过管道接收数据流,并准备好处理它所获得的数据。阅读内容后,不要忘记关闭管道。监听程序还可以通过相同的管道或另一个命名管道返回其处理的结果。这种程序间通信有时非常方便。