我已經寫了一個使用線程的python tkinter代碼,以便tkinter嚮導通過在主線程中運行的tkinter mainloop自動更新,並在單獨的線程中運行後臺進程。但是我注意到,在運行代碼的一段時間後,python崩潰了。此外,它的本質是隨機的,但大多數時候蟒蛇崩潰。我寫了一個小的測試代碼,可以顯示這個問題(我的原始代碼與此類似,但具有一些實際進程和許多其他功能,所以我共享測試代碼)。python 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.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位)。
問題
我已經提交給蟒蛇錯誤和它得到了拒絕。但我從一個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()
這個想法或者不同,或者它只是錯誤的。有關線程和GUI的問題不僅限於Tk,我知道大多數GUI工具包都會施加相同的限制:僅在GUI正在運行的線程中更新GUI。要更正您的示例,請將隊列讀取以及GUI更新移動到主線程。 'GenerateDate'繼續在他自己的線程上運行。 – mmgp
更新的代碼是有問題的,因爲現在你的主線程沒有讓工作線程運行的機會。我看到你在worker線程中放了一個'time.sleep(0)',這使得它可以控制另一個線程(在這種情況下是主線程)。現在,在您的主線程中,您正在調用'tk.after(1,...)',該函數在任何時候都不會將控制權返回給其他線程。所以,你所要做的就是在那裏也添加'time.sleep(0)'。現在兩個線程都很好地運行,允許彼此運行。 – mmgp
@mmgp - 感謝您指出。 – sarbjit