Eine Klasse mit einem Signal-Handler versehen (Linux / Unix)

Code-Stücke können hier veröffentlicht werden.
Antworten
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Hoi,

ein Ausschnitt aus einem aktuellen Projekt: Das Hauptmodul besitzt eine Klasse mit der Hauptfunktionalität des Programs und manche Methoden laufen lange, so daß es im Gebrauch und beim Testen auch zu Unterbrechungen kommen kann. Was tun, wenn das Programm lange rechnet und mittendrin unterbrochen wird, man will ja keine Daten verlieren? Eine Lösung ist sicher beständig Snapshots der Rechnungen als Dateien auszuschreiben und vom letzten Snapshot weiterzurechnen. Aber das war für mich nicht möglich.

Meine Lösung: Gebrauch des signal-Moduls. Wenn z. B. ein KeyboardInterrupt erfolgt, wird der entsprechende Handler der Klasse aufgerufen und die aktuelle Instanz wird gepickelt. Bei erneuten Aufruf des Programms kann so eine Instantisierung mit einer "fromfile"-Methode erfolgen. Das Snippet lehnt sich sehr stark an ein älteres Snippet von mir an.

Code: Alles auswählen

import signal
import pickle
import sys
# import von logging und Initialisierung des logging-Handlers
# ausgelassen.
                    
class Myclass:
    def __init__(self, data):
        self.data = data
        
        # set signal handler for keyboard interruptes
        signal.signal(signal.SIGTERM, self._onexit) # term
        signal.signal(signal.SIGABRT, self._onexit) # abort
        signal.signal(signal.SIGINT, self._onexit)  # keyboard interrupt
        # mehr Signale nach Bedarf ....
    
    def _onexit(self, signum, handler):
        logging.info("Caught signal %s." % signum
        try:
            f = open('emergencysave.dat', 'wb')
            pickle.dump(self, f, 2)
            f.close()
        except IOError, msg:
            raise IOError(msg)
        logging.info("Leaving program\nBye")
        sys.exit(signum)
        
    def tofile(self, fname):
        logging.info("pickling structure to: %s" % fname)
        try:
            f = open(fname, 'wb')
            pickle.dump(self, f, 2)
            f.close()
        except IOError, msg:
            raise IOError(msg)
        logging.info("Done\n")
        
    @classmethod
    def fromfile(obj, fname):
        logging.info("initializing structure from file: %s" % fname)
        try:
            f = open(fname, 'rb')
            obj =  pickle.load(f)
            f.close()
        except IOError, msg:
            raise IOError(msg)
            
        # set signal handler for keyboard interruptes
        signal.signal(signal.SIGTERM, obj._onexit) # term
        signal.signal(signal.SIGABRT, obj._onexit) # abort
        signal.signal(signal.SIGINT, obj._onexit)  # keyboard interrupt
        # exact dieselben Signale wie in __init__ !!!!!!!!!!!!!!!
        logging.info("Done initializing structure from file")
        return obj
Wie gesagt, das Ganze ist aus einem aktuellen Projekt von mir, besitzt noch etwas Overhead und erscheint vielleicht unaufgeräumt. Davon abgesehen hoffe ich, daß es jemand mal nützlich findet.

Gruß,
Christian

edit: Durch copy & paste entstandenen Logikfehler korrigiert.
Antworten