Я работал над tkinter
-GUI, из которого я запускаю долго работающие внешние скрипты, выходные данные которых затем записываются в GUI.Чтобы мой графический интерфейс не зависал во время работы сценариев, я использую threading
-модуль.
Это сработало в принципе, но я столкнулся с проблемой, что мой GUI часто зависал.Полагаю, что из-за того, что сценарии выдавали вывод быстрее, чем он мог отображать,
Чтобы решить эту проблему, я теперь записываю вывод своих сценариев в очередь, используя Queue
-модуль.Теперь он работает почти так, как задумано, но если у меня одновременно запущено много процессов (> 20), все они начинают работать очень медленно или, по крайней мере, выходные данные отображаются с задержкой по времени.Я предполагаю, что это потому, что очередь «не успевает» за выходными данными сценариев.
Это приводит меня к моему вопросу: есть ли способ заставить работу очереди работать быстрее, или, альтернативно, есть?способ заставить мою программу работать быстрее?
Вот минимальный пример моего кода.Вместо внешних сценариев я просто позволяю программе непрерывно считать:
import sys, os
import Tkinter as tk
from threading import Thread
import time
import Queue
class GUI:
def __init__(self,master):
self.master = master
master.title('Threading Test')
self.thread_queue = Queue.PriorityQueue()#Queue where all the outputs are lined up
self.runprocess = [0 for i in range(30)]#These will be the theads, later
#Dropdown menu that lets you select the output window
self.options = tk.StringVar()
self.options.set('1')
self.numbers = [str(q) for q in range(1,30)]
self.Option = tk.OptionMenu(master,self.options,*self.numbers,command=self.Select_Window)
self.Option.pack(fill='x')
#Button that starts function (in a thread)
self.button = tk.Button(master,text='start',command = self.run_thread)
self.button.pack()
#Output windows
self.Output_Frame = tk.Frame(master,width=800,height=100)
self.Output_Frame.pack(fill='both',expand=1)
self.Output_Frame_Pages = [0 for i in range(30)]
self.Output_Fields = [0 for i in range(30)]
self.Output_Scroll = [0 for i in range(30)]
for q in range(len(self.Output_Frame_Pages)):
self.Output_Frame_Pages[q] = tk.Frame(self.Output_Frame)
self.Output_Frame_Pages[q].place(in_=self.Output_Frame,x=0,y=0,relwidth=1,relheight=1)
self.Output_Fields[q] = tk.Text(self.Output_Frame_Pages[q],bg='white')
self.Output_Fields[q].pack(fill='both',expand=1,side='left')
self.Output_Fields[q].configure(state='disabled')
self.Output_Scroll[q] = tk.Scrollbar(self.Output_Frame_Pages[q],command=self.Output_Fields[q].yview)
self.Output_Scroll[q].pack(side='left',fill='y')
self.Output_Fields[q]['yscrollcommand'] = self.Output_Scroll[q].set
self.Output_Frame_Pages[0].lift()
#Function that checks if there is something in the queue and then writes the output
self.master.after(1,self.doWork())
#Function that lets you chose the output window
def Select_Window(self,ddmvar):
self.Output_Frame_Pages[int(self.options.get())-1].lift()
#Function that writes output
def Write_Output(self,Message,Window):
self.Output_Fields[Window-1].configure(state='normal')
self.Output_Fields[Window-1].insert(tk.END,str(Message)+'\n')
self.Output_Fields[Window-1].see(tk.END)
self.Output_Fields[Window-1].configure(state='disabled')
#Function that "does stuff"
def run(self):
i = 0
aux = int(self.options.get())
while True:
i+=1
self.thread_queue.put((i,aux))
#print 'running'
#Function that calls "run" in a thread, so GUI does not freeze
def run_thread(self):
aux = int(self.options.get())
self.runprocess[aux-1] = Thread(target=self.run)
self.runprocess[aux-1].daemon = True
self.runprocess[aux-1].start()
#Function that checks if there is something in the queue an then writes the output
def doWork(self):
try:
self.Write_Output(*self.thread_queue.get(0))
self.master.after(1,self.doWork)
except Queue.Empty:
self.master.after(1,self.doWork)
root = tk.Tk()
gui = GUI(root)
root.mainloop()
Другая проблема, которую я заметил, заключается в том, что мои потоки, похоже, продолжаются, даже если я закрываю графический интерфейс.Это видно, если я позволю своей функции не только записывать в GUI, но и позволить моей программе print
что-то.Я не знаю, связано ли это с проблемой, описанной здесь.
Заранее благодарен за вашу помощь!
Редактировать: В случае, если это имеет значение: я запускаю python 2.7 в Linux.