我编写了一个使用线程的Python tkinter代码,以便tkinter向导通过在主线程中运行的tkinter mainloop自动更新,并在单独的线程中运行后台进程。但是我注意到,在运行代码时,Python会在一段时间后崩溃。此外,它的性质是随机的,但大多数情况下Python都会崩溃。我编写了一个小的测试代码,可以展示这个问题(我的原始代码类似于这个,但具有一些真实的进程和许多其他功能,因此我分享了测试代码)。
######################################################################
# Test Code for Tkinter with threads
import Tkinter
import threading
import Queue
import time
# Data Generator which will generate Data
def GenerateData(q):
for i in range(1000000):
#print "Generating Some Data, Iteration %s" %(i)
time.sleep(0.01)
q.put("Some Data from iteration %s. Putting this data in the queue for testing" %(i))
# Queue which will be used for storing Data
q = Queue.Queue()
def QueueHandler(widinst, q):
linecount = 0
while True:
print "Running"
if not q.empty():
str = q.get()
linecount = linecount + 1
widinst.configure(state="normal")
str = str + "\n"
widinst.insert("end", str)
if linecount > 100:
widinst.delete('1.0', '2.0')
linecount = linecount - 1
widinst.see('end')
widinst.configure(state="disabled")
# Create a thread and run GUI & QueueHadnler in it
tk = Tkinter.Tk()
scrollbar = Tkinter.Scrollbar(tk)
scrollbar.pack(side='right', fill='y' )
text_wid = Tkinter.Text(tk,yscrollcommand=scrollbar.set)
text_wid.pack()
t1 = threading.Thread(target=GenerateData, args=(q,))
t2 = threading.Thread(target=QueueHandler, args=(text_wid,q))
t2.start()
t1.start()
tk.mainloop()
######################################################################
复现步骤:
如果在IDLE中打开此代码并运行它,有时会出现挂起状态。为了复现此问题,请将睡眠时间从0.01修改为0.1并运行它。之后停止应用程序,将其修改回0.01,保存并运行。这一次它会运行,但一段时间后Python会停止工作。我使用的是Windows 7(64位)。
问题:
我已经向Python错误提交了该问题,但被拒绝了。但我从stackoverflow上的一个问题中得到了使用队列写入tkinter的想法。有人能提供建议来处理它吗?
编辑后的代码:
# Test Code for Tkinter with threads
import Tkinter
import threading
import Queue
import time
# Data Generator which will generate Data
def GenerateData(q):
for i in range(1000000):
#print "Generating Some Data, Iteration %s" %(i)
time.sleep(0)
q.put("Some Data from iteration %s. Putting this data in the queue for testing" %(i))
# Queue which will be used for storing Data
q = Queue.Queue()
def QueueHandler():
global widinst, q
linecount = 0
if not q.empty():
str = q.get()
linecount = linecount + 1
widinst.configure(state="normal")
str = str + "\n"
widinst.insert("end", str)
if linecount > 100:
widinst.delete('1.0', '2.0')
linecount = linecount - 1
widinst.see('end')
widinst.configure(state="disabled")
tk.after(1,QueueHandler)
# Create a thread and run GUI & QueueHadnler in it
tk = Tkinter.Tk()
scrollbar = Tkinter.Scrollbar(tk)
scrollbar.pack(side='right', fill='y' )
text_wid = Tkinter.Text(tk,yscrollcommand=scrollbar.set)
text_wid.pack()
t1 = threading.Thread(target=GenerateData, args=(q,))
#t2 = threading.Thread(target=QueueHandler, args=(text_wid,q))
#t2.start()
widinst = text_wid
t1.start()
tk.after(1,QueueHandler)
tk.mainloop()
GenerateDate
继续在它自己的线程上运行。 - mmgptime.sleep(0)
,这使它将控制权让给另一个线程(在这种情况下是主线程)。现在,在你的主线程中,你调用了tk.after(1, ...)
,它在任何时候都不会将控制权交还给其他线程。所以,你只需要在那里也添加一个time.sleep(0)
。现在两个线程都很好地运行,允许彼此运行。 - mmgp