【问题标题】:IPC between C application and PythonC 应用程序和 Python 之间的 IPC
【发布时间】:2016-03-22 19:01:45
【问题描述】:

所以我对 IPC 比较陌生,我有一个收集数据的 c 程序和一个分析数据的 python 程序。我希望能够:

  1. 将 python 程序作为我的主 c 程序的子进程调用
  2. 将包含要处理的数据的c结构传递给python进程
  3. 从python进程返回一个int值给c程序

我一直在简单地查看管道和 FIFO,但到目前为止找不到任何信息来解决此类问题,因为据我了解,例如 fork() 只会复制调用过程,所以不是我想要,因为我试图调用不同的进程。

【问题讨论】:

  • 目前还不清楚(至少对我而言)您具体想要做什么。我认为您发布的代码不相关(或者是)?您是否想从 Python 中调用一些 C 代码,将 C 结构中显示的数据来回传递?
  • 谢谢你,Brian,我已经编辑了这个问题,让它更加专注
  • 如果可能,我会将数据序列化为字符串并将其作为参数传递给 c 程序,并将退出代码作为返回值。如果传递的数据量或返回值可能太大,这当然是不可能的。
  • 我在非常相似的情况下使用的方法是使用共享内存(使用 mmap)。要传递给 python 脚本的数据被放入共享内存中,然后调用 python 进程,然后它进行处理并将结果放回共享内存中。我写了一个library,以便在 python 方面更轻松地处理 mmap 支持的数据。如果事情比这更复杂,也许可以使用基于消息队列的方法。

标签: python c ipc


【解决方案1】:

您组织架构的方式有点混乱。你真正想要的是Message Queues。所以在你的例子中:

  • 您的 python 工作线程侦听队列 A 中要处理的新信息;
  • 您的 C 程序在队列 A 中输入数据;
  • 您的 python 工作者处理数据并将结果排队到队列 B;
  • 您的 C 程序侦听队列 B 中的新项目;

这可能会有所不同,但概念很简单。

它们很容易实现,并且有大量的库和工具可以帮助您完成这项任务。 ZeroMQ 肯定会为您服务。它适用于 C 和 Python。

【讨论】:

  • 我会看看 ZeroMQ,看看这是否也可以通过共享内存来完成会很有趣。我以前不知道消息队列,所以感谢您向我介绍这个概念
【解决方案2】:

关于 fork() 以及执行不同流程的需要。 fork() 确实创建了当前进程的副本。但这通常与exec()(各种形式之一)结合使用,以获取进程副本以执行不同的程序。

至于IPC,您有多种选择。有人提到了一个队列——但 ZeroMQ 之类的东西有点过头了。您可以使用以下几种机制之一进行IPC

  1. Pipes(命名管道或匿名)
  2. Unix 域套接字
  3. TCPUDP 通过套接字 API
  4. Shared memory
  5. Message queues

pipe 方法是最简单的。请注意,当您在 C 程序和 Python 之间来回传递数据时,您将需要担心数据的传输语法。如果您选择使用 C 结构(可能是不可移植的),则需要在 Python 端解压缩数据。否则,您可以使用一些文本格式 - sprintf/sscanfJSON 等的组合。

【讨论】:

  • 恕我直言,ZeroMQ 方法远不是矫枉过正。假设 Osmond 自己声明对于进程间通信来说是一个“相对较新”的人,ZeroMQ 的思维概念可能会挽救他的未来,以免他反复陷入如此多的困境业余/低质量原始管道/袜子并发编程的常见陷阱。 这是基于团队学习曲线和生产力的真实经验一旦将架构转移到在可扩展的正式模式中重用 ZeroMQ 工具(高度抽象的行为,而不是低级的黑客协调资源)
  • 这很好。但是 ZeroMQ(或类似的)并不总是答案。每个问题都需要合适的工具。如果我必须在两个进程之间做简单的 IPC 来完成某件事,我当然不会使用 ZeroMQ。每个工具都有其用途和位置。
  • 拥有“当你唯一的工具是锤子时,每个问题都开始像钉子。”(马斯洛的锤子)的智慧,我仍然很漂亮当然,马斯洛的锤子不是底线问题。 概率有多低新编码员将​​在合理的时间内在运行之间创建分布式 (N+M) 故障保护 (fail-safe)、性能可扩展的消息传递进程,在 C++ 中原生开发 - python - MQL4 - java - FORTRAN - LISP - Go - PHP - ...你把它们都命名为 ... C#? 我基于生活经验的猜测为零。(概率)
  • 仅仅加入那个 msgpack 可能有助于数据语法。 C 和 Python 有很好的 msgpack 库。如果需要,甚至还有用于微控制器的 msgpack 库。
【解决方案3】:

如果你的结构足够简单,你甚至可以不使用 IPC。如果您可以将其序列化作为可以用作程序参数的字符串参数,并且返回的 int 值可以在 0-127 范围内,您可以简单地:

  • 在 C 代码中:

    • 准备要传递给 Python 脚本的命令参数
    • fork-exec(假设是类 Unix 系统)具有脚本路径和脚本参数的 Python 解释器
    • 等待孩子终止
    • 读取脚本作为代码终止传递的内容
  • 在 Python 中:

    • 从命令行获取参数并重建结构的元素
    • 处理它
    • exit(n) 结束脚本,其中n 是0-127 范围内的整数,将返回给调用者。

如果以上不符合您的要求,下一个级别将是使用管道:

  • 在 C 代码中:

    • 准备 2 个管道对,一个用于 C->Python(我们称之为输入),一个用于 Python->C(我们称之为输出)
    • 将结构序列化为字符缓冲区
    • 分叉
    • 在儿童
      • 关闭输入管道的写入端
      • 关闭输出管道的读取端
      • dup 输入管道的读取端到文件描述符 0 (stdin)(请参阅 `dup2)
      • dup 将输出管道的写入端写入文件描述符 1 (stdout)
      • 使用脚本名称执行 Python 解释器
    • 在父级
      • 关闭输入管道的读取端
      • 关闭输出管道的写入端
      • 将缓冲区(如果无法先验地知道,则最终在其大小之前)写入输入文件的写入端
      • 等待子进程终止
      • 从输出管道的读取端读取返回值
  • 在 Python 中:

    • 从标准输入读取序列化数据
    • 处理它
    • 将输出整数写入标准输出
    • 退出

【讨论】:

    【解决方案4】:

    我建议查看应用程序并构建您面临的问题。

    多线程

    到目前为止,启动两个进程并不是最大的问题,正如 Ziffusion 所说,您可以让另一个进程执行其他操作。此外,还有针对 C 的 python 绑定,因此您可以创建另一个线程(不需要它是一个进程)并从 C 程序调用您的 python 例程。

    通讯

    共享信息更有趣,因为您必须解决两个问题:一个是从技术上将数据从一个地方传输到另一个地方,反之亦然;另一个是两个不同的东西如何处理相同的数据。 这涉及到消息传递模式和流程:

    • 谁生成数据?
    • 谁接收数据?
    • 在继续之前是否有一段代码在等待某事?
    • 是否需要控制在处理数据时数据会发生什么?
    • 我想自己编码吗?
    • 我可以在项目中使用库吗?
    • 有安全限制吗?
    • ...

    一旦您回答了上述问题,您就可以定义应用程序的各个部分将如何交互。一个主要区别是同步与异步。

    同步与异步

    同步意味着对于每条消息都有一个回复,该回复应该包含在一个有限(通常尽可能小)大小的时间信封中。这是为了避免延迟。 当您必须精确控制正在发生的事情,或者您需要及时对问题 提供答案 时,这种模式最适合使用。 事实上,http 是如何下载网页的:每当您加载一个网站时,您都想立即查看内容。 这是一种称为 REQuest/REPly

    的模式

    异步通常用于处理繁重的情况:数据生产者(例如数据库接口或传感器)将大量数据发送到工作线程,而无需等待答案。然后工作线程开始对数据执行其工作,并在完成后将结果发送到数据接收器/用户。 这种模式称为 PUBlish/SUBscribe。

    还有很多其他的,但这些构成了沟通的基础。

    编组

    您面临的另一个问题是如何构建数据传递、编组。 如何将数据的含义和内容从一种上下文转换为完全不同的上下文。 例如,从 C 部分到 Python 部分。 维护序列化库既繁琐又危险,更不用说容易出现向后兼容性问题。

    实施

    当您开始实施时,您通常需要最简洁、最强大的代码。这两件事显然是相互矛盾的。所以我通常会去寻找一个可以完全满足我需要的库。 在这种情况下,我的建议是尝试 ZeroMQ:它轻薄、灵活、低级。 它将为您提供一个强大的框架来连接线程、进程甚至机器。 ZeroMQ 提供了链接,但您仍然需要一个协议才能在此链接上运行。 为了避免令人难以置信的头痛并简化您在编组问题方面的工作,我建议您调查可用的编组库,使这项任务变得容易。 Cap'n protoFlatbuffers,协议缓冲区(Google,不能发布超过 2 个链接) 它们使您可以轻松地以中间语言定义数据,并从任何其他语言解析它,而无需您自己编写所有类。

    对于管道和共享内存,我的拙见是:忘记它们的存在。

    【讨论】:

    • 一个可爱的智慧,克劳迪奥。更多成员采用您的系统设计和 S/O 答案方法。 我的帽子举起来了
    • @user3666197 谢谢你的客气话。我经常尝试让我的方法更广泛。
    猜你喜欢
    • 2011-01-02
    • 1970-01-01
    • 1970-01-01
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多