如何使python的Queue.Queue工作更快?

时间:2019-02-28 10:09:26

标签: multithreading python-2.7 tkinter queue

我一直在开发<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。

1 个答案:

答案 0 :(得分:0)

使用after每毫秒调用一个函数会带来大量开销,但是在每次调用中,您只能从队列中取出一项。您正在做的只是可能效率最高的解决方案

相反,您的函数应一次将多个项从队列中拉出。确切的数字取决于许多因素,有时了解数字的最佳方法是进行实验。您可能还需要考虑使用大于1ms的值从队列中提取项目。在两次调用之间的1毫秒间隔内,它不会为tkinter提供足够的时间来处理它需要处理的所有其他事件。

例如,您可能每10毫秒就after调用一次函数,但是一次要拉出100个项目。或者,您可能每100毫秒调用一次,从而完全耗尽队列。