根据我对扭曲的理解,反应堆线程中运行的任何东西都不应该阻塞。应该将所有阻塞活动委托给其他线程,以便在完成后将回调激活回反应器线程。
那么这也适用于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()
或:
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()))
reactor.callInThread(dlg.run)
或:
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)
编辑:好吧,后两者真的搞砸了。所以我猜答案是第一个。那我的问题是:为什么?看起来这会阻塞反应堆线程。
答案 0 :(得分:10)
您的问题实际上与线程和GUI无关。你应该总是在同一个线程中使用Twisted和GTK:没有必要这样做。
您的问题是您使用的是gtk.Dialog.run()
。这是一个你永远不应该使用的API,Twisted与否。它运行一个可重入的主循环,它会导致当前的事件处理程序阻塞,但允许其他事件处理程序在堆栈中执行一个层。 GTK对重入主循环有很好的支持,但Twisted没有(这没关系,因为就像我说的那样,你不应该使用它们。)
MessageDialog.run无论如何都不会在一个线程中工作,所以你实际上没有那个选项。它将导致不可预测的行为,这可能导致您的应用程序表现奇怪或崩溃。 GTK对线程有很好的支持,但有些东西你从来不应该对一个线程做,因为它没有任何意义,这就是其中之一。
如果您处理的代码没有进行任何处理,只是想等待某些事情发生(比如等待用户按下对话框上的按钮),您应该使用返回{{1 s,而不是线程。当它发生时,Deferred
将在响应它们的位置发出信号:“response
”。您可以使用它来连接一个非常简单的函数,该函数通过对话框显示您的消息,并在完成后返回gtk.Dialog
。这是一个例子:
Deferred
答案 1 :(得分:0)
根据我对Gtk +的经验,最好的选择是在单独的线程中运行GUI。您可以通过在Gtk +主循环中运行函数来通过GUI线程进行通信(通过idle_add函数)。我不知道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函数,并且不会阻塞反应器线程。
这将在单独的线程中启动Gtk +:
import threading
import pygtk
pygtk.require('2.0')
import gtk
import gobject
def gtk_thread():
gtk.main()
threading.Thread(target=gtk_thread)
如果您需要一些复杂的GUI交互,则必须使用continuation-passing style
进行编程修改:添加了在单独的帖子中运行Gtk +的示例
答案 2 :(得分:0)
虽然不推荐和不支持,但使用Twisted 10.x时,以下代码似乎可以继续使用gtk.main()/ dialog.run()
gobject.idle_add(lambda *x: reactor.runUntilCurrent())
reactor.startRunning()
dialog.run()