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

3
我尝试使用Electron为给定的Python代码构建GUI界面。 数据流实际上很简单:用户与Electron应用程序交互,该应用程序向Python API发送请求,API处理请求并发送回复。
到目前为止,一切都很好。我阅读了不同的线程和博客文章:
1. ZeroRPC解决方案:
  1. 从node.js作为父进程生成Python API,并直接进行通信:
  1. 使用zeroMQ套接字(例如独占对?)

但在这三种解决方案中,我都遇到了同样的问题:我必须进行异步请求/回复,因为请求处理可能需要一些时间,在此期间可能已经发生了其他请求。对我来说,这看起来像是一个非常常见的模式,但我在SO上找不到任何内容,也许我不知道我正在寻找什么。

 Frontend                         Backend

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

我认为最灵活的解决方案是使用3. zeroMQ,但在网站Python文档上,我只找到了最小的工作示例,其中发送和接收都是阻塞的。
有人可以给我一些提示吗?
1个回答

2
如果您考虑使用ZeroMQ,则进入了Actor模型编程的世界。在Actor模型编程中,发送消息与接收消息是独立的(这两个活动是异步的)。
当ZeroMQ谈论发送“阻塞”时,它指的是ZeroMQ用于在传输之前排队消息的内部缓冲区已满,因此它会阻止发送应用程序,直到此队列中有可用空间。清空队列的是成功将先前的消息传输到接收器的事物,接收器具有接收缓冲区,必须由接收应用程序清空。实际传输消息的是属于ZeroMQ上下文的管理线程。
这个管理线程是关键部分;它独立于您自己的应用程序线程运行,因此它使发送方和接收方之间的通信异步化。
您可能想要使用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构建将已经解决了这个问题。但基本上它将归结为GUI事件回调发送ZeroMQ消息。您还需要编写一个回调函数,使Electron在从后端套接字接收到消息时运行。在发送和接收消息之间,前端不会阻塞。

时间

这意味着你绘制的时间图是错误的。前端可以发送任意数量的请求,但这些请求离开并到达后端之间没有时间对齐(尽管假设一切正常,第一个请求将立即到达)。发送请求或请求后,前端只需返回并继续执行其它操作(对于用户界面而言,通常仅是等待事件的事件循环管理器)。

那个后端将处于读取/处理/回复的循环中,逐个处理请求。同样,在这些回复离开并随后到达前端之间也没有时间对齐。当回复到达前端时,它会被唤醒并进行处理。


非常感谢您提供如此详细的答案!这对我思考基本设计非常有帮助。最初,我计划在单独的线程中执行“生成回复消息”,这将导致后端的不对齐。但是我发现这完全违反了Actor模型的原则,该模型旨在摆脱传统的线程处理方式。 - Yannic

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