为什么要使用命名管道而不是文件?


42

我最近阅读了有关命名管道的信息,但我不明白为什么它们存在。
我在某处读到,使用命名管道比使用文件耗时少。

为什么会这样呢?
命名管道还必须存储在内存中(并且可以交换,就像文件一样)。
据我所知,它们必须获得一个inode,该inode必须像文件一样被当前目录引用。同样,它们必须像文件一样由程序员删除。

那么优势在哪里呢?


这不是课堂作业的一部分吗?
don.joey 2014年

6
不...实际上,当我发现此问题时,我正在看一些讲义,但我无法回答...,如果这是一项作业,我看不出这有什么意义...不是在找到答案之前,我不会一直寻找答案
user3122885 2014年

Answers:


41

在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地址或侦听某些端口。


14

的确,您不会使用系统内存,但是您在示例中未使用cpu的事实仅仅是因为您不读取管道,因此进程正在等待。

考虑以下示例:

mkfifo /tmp/testpipe
tar cvf - / | gzip > /tmp/testpipe

现在打开一个新控制台并运行:

watch -n 1 'ps u -P $(pidof tar)

在第三个控制台中:

cat /tmp/testpipe > /dev/null

如果您看一下cmd手表(第二学期),它将显示CPU消耗量增加!


1
这个答案是关于c0rp的答案的
wjandrea

2

这是一个用例,其中命名管道可以通过删除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时,这会更加有趣,因为在单元死亡之前,它们的写入次数有限。

(1)显然,另一种选择是将该临时文件创建到RAM,例如,如果/ tmp已安装到RAM(tmpfs)。但是,您将受到RAM磁盘大小的限制,而“命名管道技巧”没有限制。


0

您可以让程序保持静止,并听取命名管道中的某些外部事件。一旦外部事件发生(例如,一些新数据的到达),其他程序就可以检测到该事件,该程序又打开管道进行写入,并将相关事件数据写入管道。发出close语句后,侦听程序将通过read语句通过管道接收数据流,并准备处理所获得的数据。阅读内容后,别忘了关闭管道。侦听程序还可以通过相同程序或另一个命名管道返回其处理结果。这样的程序间通信有时非常方便。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.