2016-08-07 15 views
4

Ich habe folgende Python-Skript:Kann ich irgendwie die Verwendung von time.sleep() in diesem Skript vermeiden?

#! /usr/bin/python 

import os 
from gps import * 
from time import * 
import time 
import threading 
import sys 

gpsd = None #seting the global variable 

class GpsPoller(threading.Thread): 
    def __init__(self): 
     threading.Thread.__init__(self) 
     global gpsd #bring it in scope 
     gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info 
     self.current_value = None 
     self.running = True #setting the thread running to true 

    def run(self): 
     global gpsd 
     while gpsp.running: 
     gpsd.next() #this will continue to loop and grab EACH set of gpsd info to clear the buffer 

if __name__ == '__main__': 
    gpsp = GpsPoller() # create the thread 
    try: 
     gpsp.start() # start it up 
     while True: 

     print gpsd.fix.speed 

     time.sleep(1) ## <<<< THIS LINE HERE 

    except (KeyboardInterrupt, SystemExit): #when you press ctrl+c 
     print "\nKilling Thread..." 
     gpsp.running = False 
     gpsp.join() # wait for the thread to finish what it's doing 
    print "Done.\nExiting." 

ich mit Python bin nicht sehr gut, leider. Das Skript sollte irgendwie multithread sein (aber das ist wahrscheinlich nicht wichtig im Rahmen dieser Frage).

Was mich verwirrt ist die gpsd.next() Linie. Wenn ich es richtig verstanden habe, sollte es dem Skript mitteilen, dass neue GPS-Daten erfasst wurden und bereit sind, gelesen zu werden.

Allerdings lese ich die Daten mit der unendlichen while True Schleife mit einer 1 Sekunde Pause mit time.sleep(1).

Was dies jedoch ist, ist, dass es manchmal die gleichen Daten zweimal wiederholt (der Sensor hat die Daten in der letzten Sekunde nicht aktualisiert). Ich denke, es überspringt auch irgendwie Sensordaten.

Kann ich irgendwie das Skript ändern, um die aktuelle Geschwindigkeit nicht jede Sekunde zu drucken, aber jedes Mal, wenn der Sensor neue Daten meldet? Laut Datenblatt sollte es jede Sekunde sein (ein 1 Hz Sensor), aber offensichtlich ist es nicht genau 1 Sekunde, sondern variiert in Millisekunden.

+1

https://gist.github.com/anonymous/11833e5d6ad5af1f5324639e33c02a73 –

Antwort

2

Als allgemeine Design-Regel, sollten Sie ein Thread für jeden Eingangskanal oder allgemeiner für jede "Schleife über einen blockierenden Anruf". Sperren bedeutet, dass die Ausführung bei diesem Aufruf stoppt, bis Daten eintreffen. Z.B. gpsd.next() ist so ein Anruf.

Um mehrere Eingangskanäle zu synchronisieren, verwenden Sie einen Queue und einen zusätzlichen Thread. Jeder Eingabe-Thread sollte seine "Ereignisse" in die (gleiche) Warteschlange schreiben. Der zusätzliche Thread läuft über queue.get() und reagiert entsprechend.

Von diesem Standpunkt aus muss Ihr Skript nicht Multithread sein, da es nur einen Eingangskanal gibt, nämlich die gpsd.next()-Schleife.

Beispielcode:

from gps import * 

class GpsPoller(object): 
    def __init__(self, action): 
     self.gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info 
     self.action=action 

    def run(self): 
     while True: 
     self.gpsd.next() 
     self.action(self.gpsd) 

def myaction(gpsd): 
    print gpsd.fix.speed 

if __name__ == '__main__': 
    gpsp = GpsPoller(myaction) 
    gpsp.run() # runs until killed by Ctrl-C 

Beachten Sie, wie die Verwendung des action Rückruf der Sanitär aus der Datenauswertung trennt.

Um den Poller in ein Skript einzubetten, das andere Dinge erledigt (d. H. Auch andere Threads behandelt), verwenden Sie den Warteschlangenansatz. Beispielcode, aufbauend auf der GpsPoller Klasse:

from threading import Thread 
from Queue import Queue 

class GpsThread(object): 
    def __init__(self, valuefunc, queue): 
     self.valuefunc = valuefunc 
     self.queue = queue 
     self.poller = GpsPoller(self.on_value) 

    def start(self): 
     self.t = Thread(target=self.poller.run) 
     self.t.daemon = True # kill thread when main thread exits 
     self.t.start() 

    def on_value(self, gpsd): 
     # note that we extract the value right here. 
     # Otherwise it could change while the event is in the queue. 
     self.queue.put(('gps', self.valuefunc(gpsd))) 


def main(): 
    q = Queue() 
    gt = GpsThread(
      valuefunc=lambda gpsd: gpsd.fix.speed, 
      queue = q 
      ) 
    print 'press Ctrl-C to stop.' 
    gt.start() 
    while True: 
     # blocks while q is empty. 
     source, data = q.get() 
     if source == 'gps': 
      print data 

Die „Aktion“ wir geben den GpsPoller sagt „einen Wert von valuefunc berechnen und sie in der Warteschlange gestellt“.Die Hauptschleife sitzt dort, bis ein Wert erscheint, druckt sie aus und fährt fort.

Es ist auch einfach, die Ereignisse anderer Threads in die Warteschlange zu stellen und den entsprechenden Code hinzuzufügen.

1

Ich sehe zwei Möglichkeiten:

  1. GpsPoller wird überprüfen, ob Daten ein Flag
  2. GpsPoller geändert id Daten geändert und erhöhen überprüfen und neue Daten in die Warteschlange gestellt.

Option # 1:

global is_speed_changed = False 

def run(self): 
     global gpsd, is_speed_changed 
     while gpsp.running: 
     prev_speed = gpsd.fix.speed 
     gpsd.next() 
     if prev_speed != gpsd.fix.speed 
      is_speed_changed = True # raising flag 

while True: 
     if is_speed_changed: 
      print gpsd.fix.speed 
      is_speed_changed = False 

Option # 2 (ich ziehe diese ein, da es uns von raise Bedingungen schützt):

gpsd_queue = Queue.Queue() 

def run(self): 
     global gpsd 
     while gpsp.running: 
     prev_speed = gpsd.fix.speed 
     gpsd.next() 
     curr_speed = gpsd.fix.speed 
     if prev_speed != curr_speed: 
      gpsd_queue.put(curr_speed) # putting new speed to queue 

while True: 
    # get will block if queue is empty 
    print gpsd_queue.get() 
+0

Ich würde nicht auf Geschwindigkeit verlassen wollen. Es gibt andere Daten gpsd Berichte. Selbst wenn die Geschwindigkeit gleich ist (ich fahre mit konstanter Geschwindigkeit), möchte ich immer noch die neuen Daten melden. –

+0

Ich bin mir nicht sicher, das hat so viel mit "Geschwindigkeit" zu tun, wie es "Standort". Die Standortabfrage ist wichtiger, weil alles, was gemessen wird, die gleiche konstante Geschwindigkeit haben kann, obwohl Koordinaten geändert werden, die dies nicht berücksichtigen würde ... –

+0

Auch wenn der Standort derselbe ist, denke ich immer noch, dass es gemeldet werden sollte, dh das Skript sollte mir sagen: "Hey, ich habe gerade eine Antwort von den Satelliten bekommen, dass dein Standort wirklich immer noch derselbe ist." –