Node.js/Electron和Python之间的异步IPC



我尝试使用Electron为给定的Python代码构建GUI。 数据流实际上是直截了当的:用户与Electron应用程序交互,该应用程序向Python API发送请求,后者处理请求并发送回复。

目前为止,一切都好。我阅读了不同的主题和博客文章:

  1. 零RPC解决方案:
  • https://medium.com/@abulka/electron-python-4e8c807bfa5e
  • https://github.com/fyears/electron-python-example
  1. >从节点生成Python API作为子进程.js并直接通信:
  • https://www.ahmedbouchefra.com/connect-python-3-electron-nodejs-build-desktop-apps/
  • 这对我来说似乎不是最聪明的解决方案,因为使用 zeroRPC 或 zeroMQ 可以更轻松地更改前端架构而无需接触后端代码。
  1. 使用 zeroMQ 套接字(例如独占对?
  • https://zeromq.org/socket-api/#exclusive-pair-pattern

但是在所有三个解决方案中,我在同一点上挣扎:我必须发出异步请求/回复,因为请求处理可能需要一些时间,而在这段时间内,可能会发生进一步的请求。对我来说,这看起来是一种非常常见的模式,但我在SO上什么也没找到,也许我只是不知道,我到底在寻找什么。

Frontend                         Backend
|                              |
REQ1 |—————————————————————————————>|Process REQ1——--
|                              |               |
REQ2 |—————————————————————————————>|Process REQ2 --|----—
|                              |               |    |
REP1 |<————————————————————————————-|REPLY1 <———————     | 
|                              |                    |
REP2 |<————————————————————————————-|REPLY2 <———————————--
|                              |

在我看来,最灵活的解决方案似乎是 3. zeroMQ,但在网站和 Python 文档中,我只找到了最少的工作示例,其中发送和接收都阻塞了。

谁能给我一个提示?

如果您正在考虑使用 ZeroMQ,那么您正在进入 Actor 模型编程的世界。在执行组件模型编程中,发送消息与接收该消息无关(这两个活动是异步的(。

ZeroMQ所说的阻塞是什么意思

当 ZeroMQ谈论发送"阻塞"时,这意味着 ZeroMQ 用于在传输之前对消息进行排队的内部缓冲区已满,因此它会阻止发送应用程序,直到该队列中有可用空间。清空队列的是将较早的消息成功传输到接收方,接收方具有接收缓冲区,接收应用程序必须清空该缓冲区。实际传输消息的是属于 ZeroMQ contenxt 的管理线程。

此管理线程是关键部分;它独立于您自己的应用程序线程运行,因此它使发送方和接收方之间的通信异步。

你可能想要的是使用ZeroMQ的反应堆zmq_poll((。通常在Actor模型编程中,你有一个循环,顶部是对反应堆的调用(在本例中为zmq_poll(((。Zmq_poll(( 告诉您何时发生了某些事情,但在这里您主要感兴趣的是告诉您消息已到达。通常,您会读取该消息,对其进行处理(这可能涉及发送其他 ZeroMQ 消息(,然后循环回 zmq_poll((。

后端

所以你的后端将是这样的:

while (forever)
{
zmq_poll(list of input sockets) // allows serving more than one socket
zmq_recv(socket that has a message ready to read) // will always succeed immediately because zmq_poll() told us there was a message waiting
decode req message
generate reply message
zmq_send(reply to original requester) // Socket should be in blocking mode to ensue that messages don't get lost if something is unexpectedly running slowly
}

如果您不想为多个前端提供服务,则更简单:

while (forever)
{
zmq_recv(req)  // Socket should be in blocking mode
decode req message
generate reply message
zmq_send(reply) // Socket should also be in blocking mode to ensure that messages don't get lost if something is unexpectedly running slow
}

前端

您的前端会有所不同。基本上,您需要 Electron 事件循环处理程序来接管 zmq_poll(( 的角色。在Electron中使用的ZeroMQ构建将解决这个问题。但基本上它将归结为发送 ZeroMQ 消息的 GUI 事件回调。您还必须编写一个回调,以便在消息从后端到达套接字时运行Electron。在发送和接收消息之间的前端不会有阻塞。

定时

这意味着您绘制的时序图是错误的。前端可以根据需要发送任意数量的请求,但是这些请求离开和到达后端之间没有时间对齐(尽管假设一切运行顺利,第一个请求几乎会立即到达(。发送一个或多个请求后,前端只需返回执行任何它想要的操作(对于用户界面,通常只不过是等待事件的事件循环管理器(。

该后端将处于读取/处理/回复、读取/处理/回复的循环中,一次处理一个请求。同样,这些回复离开并随后到达前端之间没有时间对齐。当回复确实回到前端时,它会唤醒并处理它。

最新更新