【问题标题】:Handle communication in multi layer application处理多层应用程序中的通信
【发布时间】:2012-08-28 19:33:47
【问题描述】:

我正在使用 Python 创建一个应用程序。

我首先设计了一个 API,它运行良好。 我现在正在设计我的 GUI。 GUI 启动一个线程,用于针对 API 执行任务。

到目前为止,我使用观察者模式来处理通过不同层的通信。 基本上,通信可以有两种类型(主要): - GUI 要求线程(以及随后的 API)开始/停止 - API 将信息返回给线程,然后传播到 GUI。

这是我正在谈论的当前架构的简单架构。 一个箭头基本上意味着“通知”。

我担心的是,当应用程序线程通信时,Gui 和 API 都会收到消息,因为他们订阅了。问题是,每条消息只能由两者中的一个阅读。

我解决这个问题的方法是将消息与 ID 一起发送。这三个元素中的每一个都有一个 id,他们知道消息是给他们的还是现在的。 但我不确定这是否是“正确的”(理解最好的)方法。如果我将来有更多的聚会怎么办?

我开始考虑某种管理器来处理通信,但它必须位于架构的顶部,我不知道如何进一步组织它:s。

我并不是要一个完整的解决方案,而是主要由更有经验的人提供想法或最佳实践;)

在这个简单的案例中,我可以继续处理多个观察者模式。 但我正在考虑将我的代码移植到服务器上。在这种情况下,我可能有不止一个线程用于应用程序,处理 API 调用将变得非常不可能。

链接到我正在谈论的代码: GUIApplicationThreadApplication API

您想查看通知和更新方法。

感谢您的任何建议!

【问题讨论】:

  • 你到底用什么来实现应用线程的通信?
  • 我使用自己编写的 Observer/Observable 模式,它发送一个字符串列表。第一个字符串是我想与之交谈的对象的 id,其余的是我的消息。那是你的问题吗?
  • 我只是想了解所需的沟通途径。如果应用程序线程只是充当其他两者之间的断点,为什么不使用 GUI/Thread 和 Thread/Api 之间的谨慎连接?
  • 如果对您有帮助,我添加了指向完整代码的链接。我不完全理解你所说的谨慎连接是什么意思。你的意思是绕过中间线程?

标签: python communication observer-pattern


【解决方案1】:

我遇到的观察者模式的一个很好的实现是 Qt 中的信号/槽系统。对象有信号,槽(实际上是方法)可以连接到信号。发出信号时调用连接的插槽。

在我看来,您的一些问题可能源于您在每个对象中都有单一的通信通道这一事实。这迫使您在每个update 方法中都有一些调度机制,并使代码相当复杂。

从 Qt 中汲取灵感,您可以为每种类型的消息和收件人提供不同的信号。信号代码如下所示:

class Signal:
    def __init__(self):
        self.subs = []

    def subscribe(self, s):
        self.subs.append(s)

    def signal(self, *args, **kwargs):
        for s in self.subs:
            s(*args, **kwargs)

例如,gui 将有一个信号stop_signal 和线程处理它的方法:

def handle_gui_stop(self):
    self.console_logger.debug("Facemovie is going to stop")
    self.my_logger.debug("Facemovie is going to stop")
    self.stop_process = True
    # ...

在初始化代码的某个地方,我们会将所有内容联系在一起:

gui.stop_signal.subscribe(thread.handle_gui_stop)

【讨论】:

  • 感谢您的回答!我认为您找到了我问题的根源,您的解决方案似乎不错。实际上,我最近一直在研究一个非常相似的解决方案,使用 json 对象而不是您的信号类(例如,它可以更轻松地创建 Web 界面)。我仍然真正想知道的是谁应该知道谁。我认为如果 GUI 对内核的了解越少越好。但在这种情况下,解决方案可能是使用相应的信号构建适当的 API。我必须进一步考虑:)
【解决方案2】:

我最近创建了一个具有类似架构(GUI 线程 + 一个单独的工作线程)的 GUI 应用程序,我最终以两个队列的形式(来自 Queue Python 模块)在线程之间创建了一个显式协议。一个队列用于 GUI 发出的请求并由工作线程使用。另一个队列用于由工作线程生成并由 GUI 使用的答案。

我发现当线程之间的通信是明确的时会更清晰,您可以完全控制更新的时间和地点(只能从 GUI 线程调用 GUI 方法)。

此模型在服务器环境中的自然扩展是消息队列协议,如 AMQP。

【讨论】:

  • 谢谢回答和关键字:)。问题是,沟通真的不是我的问题。我的问题是我有三层,而 GUI 需要来自其他层的数据。我不确定 GUI 是否真的应该知道有两层的事实。所以我的消息通过中间层。您的解决方案是否意味着我应该使用不同的技术处理每一层之间的通信?
  • 你的图层是什么?我看到了 GUI 和 API。线程不是层,如果它只调用 API。不要将模块(层)与使用模块(线程)的运行时组件混淆。此外,“通信不是问题”在多线程 GUI 应用程序中是一个有争议的声明,因为它在何时何地执行线程代码非常重要。一般来说,我建议创建一个供 GUI 使用的“服务层”(或“外观”)(因此 GUI 只知道这个服务层,而不是应用程序中的所有模块)。正如我所写,我发现显式线程间通信在 GUI 应用程序中效果最好。
  • 是的,我明白你的意思了。我所说的线程实际上是一个层。我称它为线程,因为它作为线程运行,由 GUI 启动。我确实使用 API。实际上,线程使用 API 调用来执行 GUI 要求的操作。但它比只调用一种 API 方法更聪明。基本上,我认为这就是你所说的服务层。但是来自 API 的一些消息对 GUI 本身很有用(主要用于用户信息);我希望 GUI 能看到它们。这解释了我得到的当前架构
【解决方案3】:

应用程序线程必须更明确地进行通信,因为它是 GUI 和应用程序 API 之间的通信器。这可以通过分离来自 GUI 和来自应用程序 API 的工作集(队列)来实现。此外,应用程序线程必须能够处理交付类型的模式,其中包括命令发送者和接收者。这包括管理不同队列之间的通信(例如,GUI 队列有待处理的命令,该命令正在等待应用程序 API 队列中的命令。一旦完成,应用程序线程将结果在队列之间传回)。而每个队列本身就是观察者。

在扩展应用程序方面,在我看来,您希望将来添加更多的 GUI,这将由上述请求/响应(或发送者/接收者)模式实现处理(就足够了)。

如果您计划添加更多层垂直而不是水平,那么您不应该使用相同的应用程序线程在新层之间进行通信。嗯,物理上它可以是相同的,但实际上它至少必须不同。这可以通过再次完全实现我上面描述的内容(单独的队列)来实现。通过引入动态添加队列,您将打开添加新层的可能性(新层只对应于新队列)。

【讨论】:

  • 谢谢你的答案。您是第二个谈论队列的人。毕竟,这可能是我正在寻找的词。你是对的,我未来的目标是添加 GUI。更准确地说,我使用当前的 GUI 作为开发工具和第一个版本。我的最终目标是进入云端并使用 Web 界面。但是 Python 队列是否与其他技术兼容?
  • 我无法咨询有关 Python 队列实现细节的信息。但是,将队列视为任务(命令)队列,在这里它将与任何其他平台兼容。例如App Thread 层的 App API 特定队列从 App API 接收任务,然后 App Thread 在队列中注册另一个任务,该队列特定于其他技术(例如 MS BizTalk 特定队列)并等待其完成,如前所述。但是,任务仍然在 Python 层,而是将整个系统与 BizTalk 层连接起来。在这里,它与 BizTalk 集成在一起!我认为这回答了你的问题。
  • 它确实给了我一些专业术语,当多个客户端同时访问服务器时,这些术语肯定会有所帮助。我真的很喜欢消息队列的想法我不确定您的解决方案的基本原理是否真的与我的(或其他人之一)不同。这个想法基本上是使用相同的通信技术,但要指向一个通道。我想这就是我要做的。
  • 我刚刚阅读了 Radomir Liksy 的答案,看起来很相似。我同意他并且您需要注意的一件事是,GUI 必须知道 APP API 的存在。但这里要补充的关键点是,GUI 在物理上并不使用 APP API。你会问“这两个怎么在一起?”。方法如下:使用 APP API 设计 GUI,使层模型进行通信。接下来,抽象出通信实现,引入APP Thread层,这是通信抽象的基于消息的实现。这有助于在未来优化/替换通信语义。
  • 哇,我很想围绕着咖啡讨论这个问题:)。 SO仍然无法做到的事情。不过感谢您的完整答案,我会尽力做到最好
【解决方案4】:

特别是对于 GUI,我推荐另一种模式:MVC。它包含了观察者模式,比单独的观察者模式更健壮。

它解决了你的顾虑,因为它分离了顾虑:每一层都有一个非常具体的角色,你可以改变它们中的任何一个,只要你不改变它们之间的接口。

【讨论】:

    猜你喜欢
    • 2011-10-31
    • 2011-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-08
    • 2012-06-04
    • 1970-01-01
    相关资源
    最近更新 更多