Python脚本无明显原因冻结
我对Python并不是特别陌生,但我觉得这个程序不正常工作可能有原因。我写过一个类似的程序,这个程序是从那个基础上改的,而那个程序运行得很好。这个程序是用来绘制一组ping响应的平均时间图表,以便看看一天中的时间是否有规律可循。源代码如下:
from Tkinter import *
import matplotlib
import time
import os, sys, threading, Queue
matplotlib.use('TkAgg')
from numpy import arange, array, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import Tkinter
import sys
class App(object):
def __init__(self):
self.q = Queue.Queue()
self.q2 = Queue.Queue()
self.avvals=[]
self.addlist=['bbc.co.uk', 'google.co.uk', 'nhgs.co.uk', 'bing.co.uk', 'msn.com']
self.addlistlen = len(self.addlist)
self.root = Tkinter.Tk()
self.root.wm_title("Connection Speed")
self.frame = Tkinter.Frame(self.root)
self.frame.pack(side='top', expand=1, fill='both',)
self.frame2 = Tkinter.Frame(self.frame)
self.frame2.pack(side='bottom', expand=1, fill='both',)
self.f = Figure(figsize=(5,4), dpi=100)
self.a = self.f.add_subplot(111)
self.gframe = Tkinter.Frame(self.frame)
self.gframe.pack(side='top', expand=1, fill='both',)
self.canvas = FigureCanvasTkAgg(self.f, master=self.gframe)
self.canvas.show()
self.canvas.get_tk_widget().pack(side='top', fill='both', expand=1)
self.canvas._tkcanvas.pack(side='top', fill='both', expand=1)
self.lt = threading.Thread(target=self.loop())
def getping(self, add):
pingaling = os.popen("ping -n 2 "+str(add).strip())
sys.stdout.flush()
line = pingaling.read()
if line:
try:
line = line.split('Maximum = ')[1]
time = line.split('ms, Average')[0]
self.q.put(int(time))
except:
self.q.put(None)
def gpthread(self, *a):
t = threading.Thread(target=self.getping, args=a)
t.isDaemon = True
t.start()
def loop(self):
while 1:
for x in self.addlist:
self.gpthread(x)
while self.q.qsize<self.addlistlen:
pass
tl = []
for u in range(self.addlistlen):
temp = self.q.get()
if temp != None:
tl.append(temp)
if len(tl)>0:
self.update(sum(tl)/len(tl))
else:
self.update(None)
def update(self, val):
self.a.clear()
self.avvals.append(val)
self.a.plot(self.avvals, linewidth=0.5, color = 'b')
self.canvas.draw()
a = App()
try:
a.root.mainloop()
except:
a.root.destroy()
我可能不需要底部的try..except部分,但我加上去是想看看这样做是否会有区别。我还没机会在其他电脑上试试,但我其他的脚本都运行得很好,所以……我实在搞不懂为什么它会卡住,停止响应。如果我用任何方法退出它,我会收到一个错误提示,内容是“致命的Python错误:PyEval NULL tstate”或者类似的东西。现在它甚至连展开都不行了!直接就变成不响应了!
1 个回答
6
将
self.lt = threading.Thread(target=self.loop())
改为
self.lt = threading.Thread(target=self.loop)
target=self.loop()
是在把结果传给 threading.Thread
之前,先调用了 loop
方法。
而 target=self.loop
则是把方法本身传给 threading.Thread
,而不是直接调用它。这样一来,threading.Thread
就可以在一个新的线程中调用这个方法。
下面是一段代码,它使用线程来 ping 一些 IP 地址,并在一个 Tkinter 窗口中显示平均 ping 时间的动态 matplotlib 条形图:
import Tkinter
import threading
import subprocess
import Queue
import shlex
import re
import matplotlib.pyplot as plt
import matplotlib.backends.backend_tkagg as tkagg
import atexit
import numpy as np
pingers=[]
def cleanup():
print('terminating ping subprocesses...')
for pinger in pingers:
pinger.proc.terminate()
atexit.register(cleanup)
class Pinger(threading.Thread):
def __init__(self,app,queue):
threading.Thread.__init__(self)
self.app=app
self.queue=queue
def run(self):
# One ping subprocess is started by each Pinger thread.
# The ping subprocess runs indefinitely, terminated by the cleanup function
# which is called by atexit right before the main program terminates.
ip = self.queue.get()
cmd="ping %s" % ip
self.proc = subprocess.Popen(shlex.split(cmd),
stdout=subprocess.PIPE)
for line in iter(self.proc.stdout.readline,''):
match=re.search('time=(.*)\s+ms',line)
if match:
avg=float(match.group(1))
self.app.update(ip,avg)
class App(object):
def __init__(self,master,ips):
self.ips=ips
self.fig = plt.Figure(figsize=(5,4), dpi=100)
self.fig.subplots_adjust(bottom=0.25)
self.ax=self.fig.add_subplot(1,1,1)
self.canvas = tkagg.FigureCanvasTkAgg(self.fig, master=master)
self.canvas.get_tk_widget().pack(side='top', fill='both', expand=1)
self.canvas.show()
N=len(self.ips)
self.idx=dict(zip(self.ips,range(N)))
# I set an initial ping time of 200 just to make the initial bar chart
times=[200]*N
self.rects=self.ax.bar(range(N), times)
self.ax.set_xticks(np.arange(N)+0.8*0.5)
self.ax.set_xticklabels(self.ips, rotation=25)
def update(self,ip,avg):
# This is called by Pinger threads, each time a new ping value is obtained
print(ip,avg)
self.rects[self.idx[ip]].set_height(avg)
self.canvas.draw()
def main():
root = Tkinter.Tk()
root.wm_title("Connection Speed")
ips=['bbc.co.uk', 'google.co.uk', 'nhgs.co.uk', 'bing.co.uk', 'msn.com']
app = App(root,ips)
queue = Queue.Queue()
for ip in ips:
queue.put(ip)
# This starts one Pinger for each ip.
pinger=Pinger(app,queue)
pingers.append(pinger)
pinger.daemon=True
pinger.start()
Tkinter.mainloop()
if __name__=='__main__':
main()