开发者

Python script freezes for no apparent reason (afaik)

i'm not particularly new at python but i just thought there might be a reason for this program not working properly. i have written a similar one from which this is derived, and that still works fine. it is a program to graph the average time of a set of ping responses, to see if there is any pattern in the time over the day. the source is as follows

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()

i probably dont need the bottom try..except but i put it in to check if it would make a difference. i haven't had a chance to try it on another computer, but my other scripts are working fine so.... i simply can't comprehend why it freezes, stops responding, and if i exit it by any method i get a error saying Fatal python error: PyEval NULL tstate or somthing very similar. now it doesn't even expand! it just goes straight to not responding!


Change

self.lt = threading.Thread(target=self.loop())

to

self.lt = threading.Thread(target=self.loop)

target=self.loop() calls the loop method before passing the result to threading.Thread.

Passing target=self.loop passes the method object to threading.Thread without calling it. This lets threading.Thread call the method in a new thread.


Here is some code which uses threads to ping some ips, and displays the average ping times in an animated matplotlib bar chart, embedded in a Tkinter window:

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()

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜