运行时错误:主线程不在主循环中

2024-04-25 00:53:51 发布

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

当我打电话

self.client = ThreadedClient() 

在我的Python程序中,我得到了错误

"RuntimeError: main thread is not in main loop"

我已经做了一些谷歌搜索,但不知怎的我犯了个错误。。。有人能帮我吗?

完全错误:

Exception in thread Thread-1:
    Traceback (most recent call last):
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 530, in __bootstrap_inner
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 483, in run
    File "/Users/Wim/Bird Swarm/bird_swarm.py", line 156, in workerGuiThread
    self.root.after(200, self.workerGuiThread)
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 501, in after
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1098, in _register
    RuntimeError: main thread is not in main loop

课程:

class ThreadedClient(object):

    def __init__(self):
        self.queue = Queue.Queue( )
        self.gui = GuiPart(self.queue, self.endApplication)
        self.root = self.gui.getRoot()
        self.running = True
        self.GuiThread = threading.Thread(target=self.workerGuiThread) 
        self.GuiThread.start()

    def workerGuiThread(self):
        while self.running:
            self.root.after(200, self.workerGuiThread)
            self.gui.processIncoming( )     

    def endApplication(self): 
        self.running = False

    def tc_TekenVogel(self,vogel):
        self.queue.put(vogel)

class GuiPart(object):
    def __init__(self, queue, endCommand): 
        self.queue = queue
        self.root = Tkinter.Tk()
        Tkinter.Canvas(self.root,width=g_groottescherm,height=g_groottescherm).pack()
        Tkinter.Button(self.root, text="Move 1 tick", command=self.doSomething).pack()
        self.vogelcords = {} #register of bird and their corresponding coordinates 

    def getRoot(self):
        return self.root

    def doSomething():
        pass #button action

    def processIncoming(self):
        while self.queue.qsize( ):
            try:
                msg = self.queue.get(0)
                try:
                    vogel = msg
                    l = vogel.geeflocatie()
                    if self.vogelcords.has_key(vogel):
                        cirkel = self.vogelcords[vogel]
                        self.gcanvas.coords(cirkel,l.geefx()-g_groottevogel,l.geefy()-g_groottevogel,l.geefx()+g_groottevogel,l.geefy()+g_groottevogel)            
                    else:
                        cirkel = self.gcanvas.create_oval(l.geefx()-g_groottevogel,l.geefy()-g_groottevogel,l.geefx()+g_groottevogel,l.geefy()+g_groottevogel,fill='red',outline='black',width=1)
                        self.vogelcords[vogel] = cirkel 
                    self.gcanvas.update()
                except:
                    print('Failed, was van het type %' % type(msg))
            except Queue.Empty:
                pass

Tags: inpyselfqueuemaintkinterlibdef
3条回答

因为这一切确实帮助了我的问题,但并没有完全解决,这里还有一件事要记住:

在我的例子中,我开始在许多线程中导入pyplot库并在那里使用它。在把所有的库调用移到我的主线程之后,我仍然得到那个错误。

我确实通过删除其他线程中使用的其他文件中该库的所有导入语句来消除它。即使他们没有使用这个库,同样的错误也是由它引起的。

我知道这很晚了,但我将线程设置为守护进程,没有引发异常:

t = threading.Thread(target=your_func)
t.setDaemon(True)
t.start()

在主线程之外的线程中运行主GUI循环。你不能这样做。

在一些地方,文档随意地提到Tkinter并不完全是线程安全的,但是据我所知,从来没有完全出来说你只能从主线程与Tk对话。原因是真相有些复杂。Tkinter本身是线程安全的,但是很难以多线程的方式使用。最接近官方文件的似乎是this page

Q. Is there an alternative to Tkinter that is thread safe?

Tkinter?

Just run all UI code in the main thread, and let the writers write to a Queue object…

(给出的示例代码并不好,但足以找出他们的建议并正确地执行操作。)

实际上,是一个线程安全的Tkinter,mtTkinter替代品。它的文档实际上很好地解释了这种情况:

Although Tkinter is technically thread-safe (assuming Tk is built with --enable-threads), practically speaking there are still problems when used in multithreaded Python applications. The problems stem from the fact that the _tkinter module attempts to gain control of the main thread via a polling technique when processing calls from other threads.

我相信这正是您所看到的:Thread-1中的Tkinter代码试图窥视主线程以找到主循环,但它不在那里。

所以,这里有一些选择:

  • 按照Tkinter文档的建议,从主线程使用Tkinter。可能是将当前主线程代码移动到工作线程中。
  • 如果您正在使用其他想要接管主线程的库(例如twisted),那么它可能有一种与Tkinter集成的方法,在这种情况下,您应该使用它。
  • 使用mkTkinter来解决问题。

另外,虽然我没有找到这个问题的确切副本,但还有一些相关的问题。有关详细信息,请参见this questionthis answer,以及更多信息。

相关问题 更多 >