代码之家  ›  专栏  ›  技术社区  ›  K.Mulier

Pyqt信号:被激发的信号在disconnect()后仍能正常工作吗?

  •  2
  • K.Mulier  · 技术社区  · 8 年前

    我正在处理一个应用程序,在这个应用程序中,许多信号被激发,然后重新连接。我将详细解释应用程序是如何工作的,以及我的困惑从何处开始。


    1。重新连接信号

    在我的应用程序中,我经常重新连接信号。我将使用下面的静态函数,从本帖的@ekhometo(并稍加修改)中获得: PyQt Widget connect() and disconnect()

    def reconnect(signal, newhandler):
        while True:
            try:
                signal.disconnect()
            except TypeError:
                break
        if newhandler is not None:
            signal.connect(newhandler)
    


    2。应用程序

    想象一下这个功能 emitterFunc(self) 循环浏览对象列表。在每次迭代时,函数连接 mySignal 对对象,激发信号,然后断开连接 我的签名 在下一个迭代步骤的开始。发射信号还携带一些有效载荷,例如一个物体 Foo() .


    enter image description here

    编辑:

    • 上面显示的设计是 简化了很多 . 在最后的设计中,信号发射器和接收槽可以在不同的线程中工作。

    • 因为这样会导致我们走得太远,所以我不能一次连接所有对象,发出信号,最后断开所有对象。我必须一个接一个地在它们之间循环,执行连接-发射-断开过程。

    • 又一次,由于某些原因,我们走得太远了,我不能直接打电话给这些空位。


    三。信号槽机构的心理图像

    随着时间的推移,我建立了一个关于信号槽机制如何工作的心理图像。我想象一个 信号槽引擎 吸收所有发射的信号并将它们放入队列。每个信号灯都在等待转弯。当时间准备就绪时,引擎将给定的信号传递给相应的处理程序。为了正确地做到这一点,引擎进行了一些“记账”工作,以确保每个信号最终都位于正确的位置。

    enter image description here


    4。信号槽引擎的行为

    想象一下我们在N区 钍 迭代步骤。我们联系 self.mySignal 到 对象 . 然后我们用它的有效载荷发射信号。这样做之后,我们几乎立即断开连接并建立一个新的连接 对象\n+1 . 在我们断开连接的那一刻,发射的信号可能还没起作用。我可以想象信号槽引擎的三种可能行为:

    • [选项1]发动机注意到连接断开,并丢弃 sig_n 从队列中。

    • [选项2]引擎注意到连接重新建立到另一个处理程序,并发送 西格恩 致 对象\n+1 (当它到达队列的前面时)。

    • [选项3]发动机不会改变 西格恩 . 当被激发时,它是为 对象 这就是最终的结局。


    5。我的问题

    我的 第一个问题 现在已经很明显了。正确的信号槽引擎行为是什么?我希望这是第三种选择。

    作为一个 第二个问题 我想知道给定的心理形象在多大程度上是正确的。例如,我是否可以依赖于从队列中依次发出的信号?这个问题不那么重要-它对我的应用程序当然不重要。

    这个 第三个问题 与时间效率有关。重新连接到另一个处理程序是否耗时?一旦我知道第一个问题的答案,我将继续构建应用程序,我可以自己测量重新连接时间。所以这个问题不是那么重要。但如果你知道答案,请分享:—)

    1 回复  |  直到 8 年前
        1
  •  2
  •   p-a-o-l-o    8 年前

    我先从你的开始 第二个问题 ,说你的 心理意象 部分正确,因为涉及队列,但并非总是如此。发出信号时,有三种可能的方法调用连接的插槽,其中两种方法使用事件队列(A QMetaCallEvent 在运行中实例化并用 QCoreApplication 的方法 postEvent ,其中事件目标是插槽固定器或信号接收器(如果您愿意)。第三种情况是直接调用,因此发出信号就像调用插槽一样,没有任何东西排队。

    现在到 第一个问题 :在任何情况下,当发出信号时,都会遍历连接列表(属于信号发射器),并使用上面提到的三种方法之一逐个调用插槽。无论何时建立或断开连接,列表都将更新,但这必然发生在发出信号之前或之后。简而言之:在发出信号后,成功阻止对已连接插槽的调用的机会很小,至少不会中断与 disconnect() . 所以我会标记 [OPTION 3] 正确无误。

    如果你想进一步挖掘,从 ConnectionType enum documentation 其中,三种基本类型的连接(直接连接、排队连接和排队阻塞连接)都得到了很好的解释。一 连接类型 不能指定为的第五个参数 QObject 的方法 connect 但是,正如您将从上面的链接文档中了解到的,qt本身常常选择最适合这种情况的连接类型。扰流器:涉及螺纹:)

    关于 第三个问题 :我手头没有要显示的基准测试,因此我将给出一个所谓的 主要基于意见 回答,从imho开始的回答。我认为 信号/插槽 领域是那些 保持简单 规则做规则,你的 重新连接 模式似乎使事情比需要的复杂得多。正如我上面所暗示的,当建立连接时,一个连接对象被附加到一个列表中。当信号发出时,所有连接的插槽将以某种方式被依次调用。所以,为什么不先连接所有项目,然后发出信号,然后断开所有项目,而不是在循环中的每个周期断开/重新连接/发出?

    我希望我的(长时间的,也许是TLDR)回答能有所帮助。读得好。