ubuntuusers.de

[Python] Funktion pausieren/abbrechen

Status: Gelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

moospit

Avatar von moospit

Anmeldungsdatum:
10. Juni 2007

Beiträge: 171

Wohnort: /home/franken

Hallo, bin im Moment dabei, mir ein kleines Python-Programm mit Tkinter-GUI zu schreiben mit welchem ich via SNMP dauerhaft Messwerte von angeschlossenen Geräten beziehen will. Die Ansteuerung über SNMP funktioniert wunderbar, nur habe ich das Problem, dass ich während der Messung nicht mehr auf die Funktion zugreifen kann, da die Funktion meine GUI einfriert.

Der Code sieht wie folgt aus (nur die relevanten Teile):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class SNMP(): #Klasse für SNMP
class MainWindow():
   def __init__(self,..):
      self.startb = Button(command=self.run)
      self.stopb = Button(command=self.stop)

   def run(self):
      while(1):
         # hole Werte vom entsprechenden Gerät
         # verarbeite Werte

   def stop(self):
      # soll self.run anhalten/beenden

Das Programm funktioniert wunderbar, nur würde mich interessieren, ob ich die Funktion run auch ohne Threading über die GUI pausieren/beenden kann.

mfg moospit

Lunar

Anmeldungsdatum:
17. März 2006

Beiträge: 5792

moospit schrieb:

Das Programm funktioniert wunderbar, nur würde mich interessieren, ob ich die Funktion run auch ohne Threading über die GUI pausieren/beenden kann.

Nein.

dauerbaustelle

Avatar von dauerbaustelle

Anmeldungsdatum:
2. Juli 2007

Beiträge: 1936

moospit schrieb:

Das Programm funktioniert wunderbar, nur würde mich interessieren, ob ich die Funktion run auch ohne Threading über die GUI pausieren/beenden kann.

Wie meinen?

moospit

(Themenstarter)
Avatar von moospit

Anmeldungsdatum:
10. Juni 2007

Beiträge: 171

Wohnort: /home/franken

Ich meine damit, dass man, da die Anwendung nicht zeitkritisch ist, in die Schleife folgendes einbaut:

1
2
3
4
5
6
7
8
b = true
while b == true:
  #mach etwas
  1 sekunde auf eingabe warten
  if eingabe:
    b = false
  else:
    #weitermachen

Ich will also während der Schleife mittels eines Timers für 1 Sek pro Durchlauf auf eine Eingabe (Return, etc.) warten, und falls diese gemacht wird, so soll die Bedingung für die Schleife geändert werden.

mfg moospit

dauerbaustelle

Avatar von dauerbaustelle

Anmeldungsdatum:
2. Juli 2007

Beiträge: 1936

D.h. der User hat nur 1 Sekunde Zeit etwas einzugeben? Evtl. solltest du das Prinzip nochmals überdenken...

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Warum überhaupt Tastatureingaben bei einer GUI? Threads sind doch perfekt für dein Problem. Du baust zwei Buttons für Stopp und Pause ein, und die beeinflussen den Thread dann entsprechend. Was hast du also gegen diese Lösung?

Wenn es dir darum geht, die bisherigen Ergebnisse nach der Pause zu sehen, dann mach das z.B. so:

1
2
3
ergebnisse = []
while True:
    ergebnisse.append(hole_ergebnis())

hole_ergebnis() holt dabei immer nur ein Ergebnis.

Und die while-Schleife wäre dein Thread, den du nach Belieben anhalten und weiterlaufen lassen (oder ganz abbrechen) kannst.

Alternativ könnte hole_ergebnis() ja auch yield'en (sollte dann korrekterweise hole_ergebnisse() heißen), statt zu return'en. Das wäre dann sogar schneller als eine Liste.

moospit

(Themenstarter)
Avatar von moospit

Anmeldungsdatum:
10. Juni 2007

Beiträge: 171

Wohnort: /home/franken

Ich lasse in der Konsole einen Log mitlaufen. Nun habe ich mir gedacht, da die SNMP-Verbindung samt Verarbeitung der Daten keine 2 Sekunden braucht, ein optisches Signal zu setzten, sobald der Benutzer die Eingabe machen kann. Muss ausserdem nicht anwenderfreundlich sein, da ich es nur selbst benutze und die Funktion nicht sehr oft brauchen werde,.

mfg moospit

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Dann würde der Warte-auf-Eingaben Thread nach jedem Messergebnis gestartet und nach time.sleep(2) wieder beendet werden.

Das Abfangen der Eingaben könnte so aussehen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python

import termios
import tty
import sys


def getkey():
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(sys.stdin.fileno())
        key = sys.stdin.read(1)
        if key == '\x1b':
            key = key + sys.stdin.read(2)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return key


if __name__ == '__main__':
    print "Press a key..."
    print repr(getkey())

moospit

(Themenstarter)
Avatar von moospit

Anmeldungsdatum:
10. Juni 2007

Beiträge: 171

Wohnort: /home/franken

Bin jetzt doch auf Threads umgestiegen, scheint einfacher zu sein. Jedoch hängt sich mein Programm auf, wenn ich den Thread beenden will.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
import thread, time
...

CANCEL_FLAG = None
RUNNING_FLAG = None

...

def funktion():
   global RUNNING_FLAG, CANCEL_FLAG
   if RUNNING_FLAG is None:
      RUNNING_FLAG = 1
      while CANCEL_FLAG is None:
         #Hier wird die Funktion ausgeführt

def start_function():
   if RUNNING_FLAG is None:
      thread.start_new_thread(funktion, (), {})
   start['state'] = 'disabled'

def cancel_funktion():
   while RUNNING_FLAG:
      CANCEL_FLAG = 1
      time.sleep(.1)
   start['state'] = 'normal'

...
# Hier die dazugehörigen GUI-Elemente
start = Button(root, text='Start', command=start_funktion)
cancel = Button(root, text='Abbrechen', command=cancel_funktion)
...
root.mainloop()
...

dauerbaustelle

Avatar von dauerbaustelle

Anmeldungsdatum:
2. Juli 2007

Beiträge: 1936

global ist hier nicht nötig, weil auf Variablen auf Modulebene von überall aus zugegriffen werden kann. global sollte IMMER vermieden werden!

Dass sich das Programm aufhängt liegt daran, dass sich deine cancel-Funktion dauernd wiederholt, weil das RUNNING_FLAG NIE auf False bzw. 0 gesetzt wird.

GROSSSCHREIBWEISE sollte nur bei Konstanten verwendet werden (in Python also Variablen deren Wert sich im Programmfluss nie ändert), deine Variablen ändern sich aber.

moospit

(Themenstarter)
Avatar von moospit

Anmeldungsdatum:
10. Juni 2007

Beiträge: 171

Wohnort: /home/franken

Tausend Dank. Auf das Setzten des Flags hätt ich selber kommen müssen, aber manchmal hat man ein Brett vor dem Kopf 😉

mfg moospit

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Ein paar Anmerkungen zum Stil noch: Dass Funktionen Funktionen sind, sieht man auch ohne dass es dahinter steht. 😉 Bei den Flags genau so - und wie schon gesagt wurde: Klein schreiben. Außerdem würde ich statt None/1 besser False/True verwenden. Für solche Sachen sind sie nämlich eigentlich auch gedacht. Und in Zeile 12+18 reicht auch ein if not running, was sogar etwas "menschlicher" klingt. ☺

Antworten |