twisted+gtk:我应该在线程中还是在reactor线程中运行GUI?

2024-05-17 11:36:24 发布

您现在位置:Python中文网/ 问答频道 /正文

根据我对twisted的理解,在reactor线程中运行的任何东西都不应该阻塞。所有的阻塞活动都应该委托给其他线程,以便在执行完回调后将其返回到reactor线程中。在

那么这也适用于gtk吗?例如,如果连接。。。失败。我需要:

def connectionFailed(self, reason):
    dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
                      buttons=gtk.BUTTONS_CLOSE,
                      message_format="Could not connect to server:\n%s" % (
                          reason.getErrorMessage()))
    dlg.run()

或者:

^{pr2}$

或者:

def connectionFailed(self, reason):
    def bloogedy():
        dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
                          buttons=gtk.BUTTONS_CLOSE,
                          message_format="Could not connect to server:\n%s" % (
                              reason.getErrorMessage()))
        dlg.run()
    reactor.callInThread(bloogedy)

是吗?在

编辑:哦,好吧,后两个真的搞砸了。所以我想答案是第一个。我的问题是:为什么?看起来这会阻塞反应器线程。


Tags: selfmessagegtkclosedeftypeerror线程
3条回答

你的问题实际上与线程和gui没有任何关系。您应该始终使用来自同一线程的Twisted和GTK:没有必要另外做。在

您的问题是您正在使用gtk.Dialog.run()。不管是否扭曲,这是一个绝对不应该使用的API。它运行一个可重入的主循环,这会导致当前事件处理程序阻塞,但允许其他事件处理程序在堆栈下一层执行。GTK对可重入的主循环有很好的支持,但是Twisted没有(这没关系,因为正如我所说,您不应该使用它们)。在

在消息对话框.run不管怎样,在一个线程中都不能工作,所以你实际上没有这个选项。它将导致不可预测的行为,从而导致应用程序行为异常或崩溃。GTK对线程有很好的支持,但是有些事情你永远不应该用线程来做,因为它没有任何意义,这就是其中之一。在

如果您正在处理的代码没有进行任何处理,但只想等待某件事情发生(例如等待用户按对话框上的按钮),则应该使用返回Deferreds的函数,而不是线程。如果发生这种情况,gtk.Dialogs将在它们被响应的点发出一个信号:“^{}”。您可以使用它来连接一个非常简单的函数,该函数用一个对话框显示您的消息,并在消息完成时返回一个Deferred。下面是一个例子:

def showMessage(text):
    mdlg = gtk.MessageDialog(type=gtk.MESSAGE_INFO,
                             buttons=gtk.BUTTONS_CLOSE,
                             message_format=text)
    result = Deferred()
    def response(dialog, response_id):
        mdlg.destroy()
        result.callback(response_id)
        return False
    mdlg.connect("response", response)
    mdlg.show_all()
    return result

虽然不推荐也不受支持,但是对于Twisted 10.x,下面的代码似乎可以继续使用gtk.main公司() / 对话.运行()

  gobject.idle_add(lambda *x: reactor.runUntilCurrent())
  reactor.startRunning()    
  dialog.run()

根据我使用Gtk+的经验,最好的选择是在单独的线程中运行GUI。您可以通过在Gtk+主循环中运行函数(通过idle_add函数)与GUI线程进行连接。我不知道reactor,但是从您的例子来看,从GUI进行通信的相同方式是可能的。在

例如,像这样(抱歉,我还没有测试代码):

def connectionFailed(self, reason):
    def frob():
        dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
                          buttons=gtk.BUTTONS_CLOSE,
                          message_format="Could not connect to server:\n%s" % (
                              reason.getErrorMessage()))
        dlg.run()
    gobject.idle_add(frob)

(除此之外,gtk.main公司必须在自己的线程上运行)

这将在Gtk+线程中运行frob函数,并且不会阻塞reactor线程。在

这将在单独的线程中启动Gtk+:

^{pr2}$

如果需要一些复杂的GUI交互,则必须使用continuation-passing style进行编程

编辑:添加了在单独线程中运行Gtk+的示例

相关问题 更多 >