【问题标题】:Is it possible to duplicate a pipe in Python, so that it has one write end but two read ends?是否可以在 Python 中复制管道,使其具有一个写入端但有两个读取端?
【发布时间】:2013-08-11 16:55:59
【问题描述】:

假设我有一个生成一些数据的进程,并且这些数据被两个相互独立的不同进程使用。

解决此问题的一种方法是将生成的数据写入文件,然后让其他两个进程从文件中读取。如果文件大小不大,这可以正常工作,但如果有大量数据,则 IO 会变得昂贵。

如果我只有一个进程使用数据,我可以使用os.pipe() 连接这两个进程,并将数据从一个进程的输出汇集到另一个进程的输入。

但是,由于我有两个消费者进程,我不确定是否有办法复制管道的读取端,以便两个消费者都可以从中读取。

【问题讨论】:

  • 生产者不能把相同的数据输出到两个不同的输出管道吗?
  • 您的目标是什么平台?
  • 两个进程都想要所有数据?我认为您必须发送两次数据。文件或 mmap 文件的一个优点是您不会因为其中一个进程读取数据的速度很慢而导致程序停止运行。
  • @SvenMarnach,我只针对 CentOS 5/6,所以特定于操作系统的解决方案很好。

标签: python subprocess multiprocessing


【解决方案1】:

管道中的数据只能读取一次。但是,您可以使用一个中间过程来简单地复制数据并将其写入两个不同的文件描述符。在 Unix 系统上,这是由标准工具 tee 完成的。 POSIX shell 中的一个示例:

$ exec 4> a
$ seq 3 | tee /dev/fd/4 > b

这会将seq 3 的输出写入ab 这两个文件。

您可以在 Python 中做同样的事情,使用组合 od 一次调用 os.pipe() 和调用 subprocess.Popen() 用于 tee 进程,以及一次调用 subprocess.Popen() 用于您想要的每个进程连接。

producer = subprocess.Popen(["seq", "3"], stdout=subprocess.PIPE)
pipe_r, pipe_w = os.pipe()
tee = subprocess.Popen(["tee", "/dev/fd/{}".format(pipe_w)],
                       stdin=producer.stdout, stdout=subprocess.PIPE)
consumer1 = subprocess.Popen(["cat"], stdin=tee.stdout)
consumer2 = subprocess.Popen(["cat"], stdin=pipe_r)
producer.wait()
tee.wait()
consumer1.wait()
consumer2.wait()
os.close(pipe_r)
os.close(pipe_w)

【讨论】:

  • 我已经复制粘贴了这段代码,但我得到: tee: /dev/fd/5: No such file or directory, 1 2 3 作为输出,然后死锁。有什么建议吗?
  • @gospes 这似乎在 Python 3 中不起作用——我目前没有时间找出原因。
【解决方案2】:

因此,由于它是由 Pipe 返回的文件描述符,我很遗憾地说您无法返回;不过,一个想法是让任一读取器进程将数据添加到multiprocessing.Queue,在那里两者都可以读取并随后删除数据。

您也可以始终拥有从写入器进程到每个读取器的管道。还有其他东西,例如shared memorydbus,您可以用来传送数据。

您能否更深入地描述您的问题?

根据平台,您也可以让流程使用多个流 - 例如stdout 和第 4 个 - 但这不能在操作系统之间移植。

【讨论】:

  • 我认为os.pipe() 返回的是文件描述符而不是文件对象。
  • 对不起,你是对的——文件对象实际上也指的是文件描述符;但它们都是流,因为它们依赖于
猜你喜欢
  • 2017-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多