我一直在开发<img th:src="@{data:image/png;base64,YOUR IMAGE BASE 64}
-GUI,从中开始长时间运行的外部脚本,然后将其输出写入GUI。为了使我的GUI在脚本运行时不会冻结,我使用tkinter
-模块。
这在原则上是可行的,但是随后我遇到了我的GUI经常崩溃的问题。我想因为脚本给它的输出快于其显示的速度。
要解决此问题,我现在使用threading
模块将脚本的输出写入队列。现在它几乎可以按预期运行,但是如果我同时运行多个进程(> 20),则所有进程都开始变得非常缓慢,或者至少显示输出具有时间延迟。我猜这是因为队列“跟不上”脚本的输出。
这引出我的问题:是否有办法使队列工作更快,或者有办法使我的程序工作更快?
这是我的代码的最小示例。不用外部脚本,我只是让程序不断计数:
Queue
我注意到的另一个问题是,即使关闭了GUI,我的线程也似乎继续运行。如果我让我的函数不仅写入GUI,而且让我的程序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()
东西,也可以看出这一点。不过,我不知道这是否与这里描述的问题有关。
在此先感谢您的帮助!
编辑:如果有关系:我在Linux上运行python 2.7。
答案 0 :(得分:0)
使用after
每毫秒调用一个函数会带来大量开销,但是在每次调用中,您只能从队列中取出一项。您正在做的只是可能效率最高的解决方案
相反,您的函数应一次将多个项从队列中拉出。确切的数字取决于许多因素,有时了解数字的最佳方法是进行实验。您可能还需要考虑使用大于1ms的值从队列中提取项目。在两次调用之间的1毫秒间隔内,它不会为tkinter提供足够的时间来处理它需要处理的所有其他事件。
例如,您可能每10毫秒就after
调用一次函数,但是一次要拉出100个项目。或者,您可能每100毫秒调用一次,从而完全耗尽队列。