【问题标题】:FIFO (named pipe) messaging obstaclesFIFO(命名管道)消息传递障碍
【发布时间】:2010-10-29 23:01:36
【问题描述】:

我计划使用 Unix 命名管道 (mkfifo) 进行简单的多进程消息传递。 一条消息只是一行文本。

你会阻止我这样做吗?我应该期待什么障碍?

我注意到了这些限制:

  1. 在收到邮件之前,发件人无法继续。
  2. 接收器被阻塞,直到有一些数据。需要非阻塞 IO 当我们需要停止阅读时。例如,另一个线程可能会要求这样做。
  3. 接收方可以在一次读取中获得许多消息。这些必须处理 在退出之前。
  4. 原子消息的最大长度限制为 4096 字节。这是 Linux 上的 PIPE_BUF 限制(参见 man 7 pipe)。

我将在 Python 中实现消息传递。但总体而言,障碍仍然存在。

【问题讨论】:

  • 您希望有多少进程同时使用管道?如果您有多个读者,则只有其中一个读者 AFAIR 可以看到书面信息。 (这不是 100% 确定的)
  • @rodion -- 是的,它旨在仅在一个阅读器中看到一条消息。 FIFO 就是这样工作的。
  • 为什么会出现阻塞问题?我可以看到一个非阻塞写入。当你在等待工作时,我看不到非阻塞读取的意义。
  • 在很多情况下,您都需要非阻塞读取(您可以使用 select)。例如,多个编写器不同的管道,所以你不想只阻塞一个。另一种情况是,如果您的工作不是“基于请求”的,例如您通过管道获得更新,并希望在等待更新的同时继续工作。第三种是您可以一次处理多组消息,因此您希望获得所有可用的消息。
  • 我将通过“扇入”(多输入 FIFO),这是有道理的。在这种特定情况下,不基于请求是没有意义的。批次没有意义;管道的缓冲就是您所需要的所有“批处理”。

标签: python linux unix pipe named-pipes


【解决方案1】:
  1. 缺乏可移植性 - 它们主要是 Unix 的东西。套接字更便携。
  2. 难以横向扩展到多个系统(另一个套接字+)
  3. 另一方面,对于同一台机器上的进程,我相信管道比套接字更快(通信开销更少)。

至于你的限制,

  1. 您可以在管道上使用“select”来进行非阻塞读取。
  2. 我通常(在 perl 中)在由“\n”分隔的管道上打印出我的消息,并从中读取一行以一次获取一条消息。
  3. 请注意原子长度。

我发现perlipc 是各种选项之间的一个很好的讨论,尽管它有 perl 特定的代码。

【讨论】:

  • 接收器中的 readline() 不会使您免于在内部缓冲区中保存多条消息。它们仍应在退出前进行处理。
【解决方案2】:

发送方和接收方的阻塞都可以通过非阻塞 I/O 解决。

FIFO的进一步限制:

  • 一次只有一个客户。
  • 客户端关闭FIFO后,服务端需要重新开启端点。
  • 单向。

我会改用UNIX domain sockets,它没有上述限制。

作为一个额外的好处,如果你想扩展它以在多台机器之间进行通信,它几乎没有任何变化。例如,只需查看socket 上的 Python 文档页面并将 socket.AF_INET 替换为 socket.AF_UNIX,将 (HOST, PORT) 替换为 filename,它就可以工作

SOCK_STREAM 会给你类似流的行为;也就是说,两个发送可以合并为一个接收,反之亦然。 AF_UNIX 也支持SOCK_DGRAM:保证数据报作为一个单元被发送和读取,或者根本不被读取。 (类似地,AF_INET+SOCK_STREAM=TCP,AF_INET+SOCK_DGRAM=UDP。)

【讨论】:

  • “一次只有一个客户”是什么意思?我可以在一个 FIFO 上有多个写入器和读取器。
  • 多次读取需要打开FIFO。在同一个侦听套接字上接受新连接要干净得多。
  • 仅供参考,显然在某些 unix 平台 (Solaris) 上,FIFO 是双向的。但您的观点是有效的。请改用 unix 域套接字。
  • 在编写器方面,您不能打开命名管道以在非阻塞模式下写入,除非已经存在读取器(您获得 ENXIO)。 OTOH,在读者方面,我没有看到任何迹象表明作者完成后会导致任何问题。
猜你喜欢
  • 2012-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多