在Shell/文件系统中如何使用非阻塞/异步FIFO(命名管道)?

10
有没有办法在shell中创建非阻塞/异步命名管道或类似的东西?以便程序可以将行放入其中,这些行将留在RAM中,当某个程序从管道中读取某些行时,将保留它没有读取的内容在FIFO中。很可能会有程序同时写入和读取此FIFO。起初我认为可能可以使用文件来实现,但在搜索了一段时间网络之后,似乎从文件同时读取和写入不会有好处。命名管道几乎可以工作,只是存在两个问题:首先,如果另一端没有人,则会阻止读取/写入;其次,即使我让写入被阻止并设置两个进程以在没有人读取时写入 pipe,通过尝试使用每个进程写入一行,然后尝试head -n 1 <fifo>,我只能得到一个我需要的行,但是两个写入进程终止,并且第二行丢失了。有什么建议吗?
编辑:也许可以使用一些中间程序来协助处理,充当写入者和读取者之间的中介者?

2
您可以执行类似于 mkfs /dev/ram1 1048576(如果需要,可以使用更大的数字)并将 /dev/ram1 挂载到任何地方。那可能是您能够获得的最接近“非阻塞”的方式。当然,默认情况下它完全不是非阻塞的,只是非常快速(但默认情况下命名管道也不是非阻塞的)。非阻塞操作是程序需要在文件描述符上设置的内容。 - Damon
我考虑过这个选项,在tmpfs或类似的地方创建文件,但是再次出现同时读写的问题。更像是不断写入的问题,因为它是一个文件。一个程序向文件末尾写入,另一个从开头读取一些信息,现在需要删除前几行,所以需要同时在末尾写入并在前面删除,我找不到解决方法,否则我会使用它。 - morphles
1
如果不写程序,要做这样的事情是很难(甚至是不可能的)。有一种几乎可以工作的方法:重命名是原子操作,所以每个生产者可以将每个单独的任务写入一个临时文件中,关闭文件并根据某个“众所周知”的模式进行重命名。每个消费者可以将下一个文件重命名为随机名称(这样其他消费者就不会选择它),读取内容,并删除该文件。但这只适用于每个任务级别(无论生产者以什么单位写入),而不是每行级别。 - Damon
编写一个连接到两个管道(一个读取和一个写入)并进行一些自己的缓冲的小程序真的不在话下?基本上像 tee 一样,还有一个私有映射的副本。这可能会做你想要的事情。 - Damon
是的,我考虑过使用其他程序来添加缓冲区,但也许已经有一些可以用于此目的的程序了。 - morphles
1个回答

5
您可以使用特殊的程序来实现这个目的——buffer。Buffer旨在尝试保持写入侧持续繁忙,以便在写入磁带驱动器时可以进行流式传输,但您也可以将其用于其他目的。在内部,buffer是一对通过共享内存中的大型循环队列进行通信的进程,因此您的进程将异步工作。如果队列已满,则读取进程将被阻塞,如果队列为空,则写入进程将被阻塞。示例:
bzcat archive.bz2 | buffer -m 16000000 -b 100000 | processing_script | bzip2 > archive_processed.bz2 http://linux.die.net/man/1/buffer

谢谢您指出我不知道的程序,看起来很有趣,可能在某些情况下会有用。虽然它不完全是我想要的,我将无法使用它实现我想要的功能,但我已经决定最有可能为类似我的情况实现自己的程序/守护进程。 - morphles
另一种解决方案是使用队列守护程序,类似于gearman。你的"lines"可以作为任务持久保存在memcache中。 - Ramunas Dronga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接