Tkinter和线程。堆栈空间(无限循环?)

时间:2014-03-20 18:13:19

标签: python multithreading tkinter

我正在尝试使用Tkinter和线程机制。任何人都可以解释为什么这会引发异常:

<class '_tkinter.TclError'> out of stack space (infinite loop?)

我该如何解决这个问题?下面是代码。顺便说一句,我知道有些人建议使用线程模块而不是线程,但是现在我想使用更简单的线程模块来介绍自己的机制。

from Tkinter import *
import thread
import time

def main_thread(master):

    try:
        frame = Frame(master)
        frame.pack(side='bottom')
        scrollbar = Scrollbar(master)
        scrollbar.pack(side='right',fill='y')

        t = "Title"
        title = StringVar()
        title.set(t)
        ttl = Label(master, textvariable=title, font=("Helvetica", 18))
        ttl.pack(side='top')
        cont = Text(master, font=("Helvetica",14), yscrollcommand=scrollbar.set)
        cont.pack(side='bottom')
        button = Button(frame,text="Exit", command=root.destroy)
        button.pack(side='bottom')

        n = 0
        while 1:
            n += 1
            cont.insert('end', str(n)+"\n")
            time.sleep(1)

    except Exception as e:
        print type(e), e

if __name__ == '__main__':

    root = Tk()
    root.title("My counting application")
    thread.start_new_thread(main_thread, (root,)) # FIXME: out of stack space (infinite loop?)
    root.mainloop()

谢谢你, 卢卡


修改

我解决了替换

    n = 0
    while 1:
        n += 1
        cont.insert('end', str(n)+"\n")
        time.sleep(1)

    n = 0
    def do_every_second(n):
        cont.insert("end", str(n) + "\n")
        n += 1
        master.after(1000, do_every_second, n)
    do_every_second(n)

并致电

main_thread(root)

而不是

thread.start_new_thread(main_thread, (root,))

2 个答案:

答案 0 :(得分:4)

您的代码中存在一些致命缺陷。首先,您无法编写从多个线程触及tkinter小部件的代码。您正在主线程中创建根窗口,因此您只能直接从主线程访问窗口小部件。 Tkinter不是线程安全的。

第二个问题是你有一个无限循环,不断附加到文本小部件。它别无选择,只能最终耗尽内存。

要解决您的问题,您应该:

  1. 没有永久附加到文本小部件的无限循环
  2. 不能从多个线程访问任何小部件
  3. 如果你想每秒运行一次函数,那么有比使用线程更好的方法。简而言之:

    def do_every_second():
        cont.insert("end", str(n) + "\n")
        root.after(1000, do_every_second)
    

    这将导致do_every_second做它做的任何事情,然后安排自己在将来一秒钟再次被调用。

答案 1 :(得分:-1)

错误是正确的 - 在tkinter个元素之一上存在无限循环。 thread模块与它无关。导致错误的特定行:

cont.insert('end', str(n)+"\n")

由于cont是一个tkinter元素,因此无法在无限循环中运行它。要做你想做的事,你需要打印到控制台。如果用简单的替换违规行,可以证明这一点:

print(str(n)+"\n")

编辑:如果您真的希望达到原先预期的相同效果,this post会处理潜在的替代方案。

Edit2:我认为异常是tkinter库的设计选择(虽然我不是专家)。这是有道理的,因为tkinter已经为其事件循环使用了无限循环。我认为无限循环会阻止tkinter将更改绘制到屏幕上,而是库作者选择抛出异常。 print应该有效,因为没有什么新东西可以绘制,加上它自己的线程允许tkinter的事件循环继续。< / p>