2016-03-31 16 views
1

Hallo Ich eingebettet eine Zeitbeschränkung in meinem Python-Code, der einen Fortran-Code mit einer Funktion ausgeführt wird. Allerdings erkannte ich, dass die Funktion, die eine Zeitbeschränkung für die andere Funktion setzt, den Code nicht beendet, sondern nur im Hintergrund belässt und stattdessen überspringt. Was ich tun möchte, ist den Code zu beenden, wenn es die eingeschränkte Zeit überschreitet. Hier ist der Code, den ich verwende, um die Zeit einzuschränken, die von here genommen wird.Beenden eines Programms in Python

def timeout(func, args=(), kwargs={}, timeout_duration=15, default=1): 
    import signal 

    class TimeoutError(Exception): 
     pass 

    def handler(signum, frame): 
     raise TimeoutError() 

    # set the timeout handler                                    
    signal.signal(signal.SIGALRM, handler) 
    signal.alarm(timeout_duration) 
    try: 
     result = func(*args, **kwargs) 
    except TimeoutError as exc: 
     result = default 
    finally: 
     signal.alarm(0) 

    return result 

Ich sah popen.terminate() auf, sys.exit() und atexit.register() kann aber nicht herausfinden, wie es mit diesem Stück Code arbeiten, die ich weiter unten, dass ich in Kommentar in Teil hinzuzufügen versucht zeigte.

... 
     result = func(*args, **kwargs) 
    except TimeoutError as exc: 
     result = default 
#add the terminator 
    finally: 
... 

HINWEIS: Die Funktion ist innerhalb einer for-Schleife Kette so möchte ich nicht ganze Python-Sitzung töten, sondern wollen nur das Programm töten, die diese Funktion ausgeführt wird, die ein Fortran-Code ist und in der mit dem anderen Element überspringen für Schleife Kette.

Teil unten hinzugefügt, nachdem einige Kommentare und Antworten:

Ich versuchte SIGTERM mit popen.terminate hinzufügen() aber es beendete all Python-Session, die ich will nur laufende Sitzung beenden und zu den anderen Elementen überspringen in die for-Schleife. was ich tat, ist wie folgt:

... 
    signal.signal(signal.SIGTERM, handler) 
    signal.alarm(timeout_duration) 
    try: 
     result = func(*args, **kwargs) 
    except TimeoutError as exc: 
     result = default 
     popen.terminate() 
... 
+0

Was meinen Sie mit * "das Programm, das diese Funktion ausführt" *? Handelt es sich um einen externen Prozess, der von einem "Subprozess" -Modul gestartet wird? Gibt es absteigende Prozesse? Wird der Prozess beendet, wenn Sie das Signal SIGTERM senden? Was ist deine Python-Version? Es sollte ausreichen, um den 'timeout' Parameter an' process.wait() 'zu übergeben und' process.terminate() 'bei TimeoutError aufzurufen, wenn keine Nachkommen vorhanden sind und der Prozess auf' SIGTERM' beendet wird. – jfs

+0

@ J.F.Sebastian dieser Code führt eine Funktion, die einen Fortran-Code ausführt, die ich die Laufzeit beschränken möchte, um von CPU zu speichern. All diese Funktion macht den Fortran-Code im Hintergrund und springt zu dem anderen Element in der for-Schleife, die sich in CPU nach 100 Zyklen anhäuft, sagen wir also, ich möchte die Sitzung beenden, bevor ich zu dem anderen Element überspringe. Python-Version 2.7. – jackaraz

+0

Möglicherweise verwandt: [Führen Sie einen Befehl für eine bestimmte Zeit und dann abgebrochen, wenn die Zeit überschreitet] (http://unix.stackexchange.com/q/23145) – GingerPlusPlus

Antwort

1

Sie nicht die Signal-Handler eine Ausnahme erwarten Anheben durch den Call-Stack vermehrt werden, ist in einem anderen Kontext aufgerufen.

popen.terminate() wird SIGTERM auf Posix-Systeme erzeugen, so dass Sie ein Signal-Handler für SIGTERM und nicht SIGALRM haben sollte.

Anstatt eine Ausnahme in Ihrem Signalhandler auszulösen, sollten Sie eine Variable festlegen, die Sie regelmäßig überprüfen, um die Aktivität zu stoppen. Wenn Sie keinen Signalhandler für SIGTERM haben, wird der Standardhandler wahrscheinlich eine KeyboardInterrupt Ausnahme erzeugen.

+0

Also schlagen Sie vor, popen.terminate() mit SIGTERM zu verwenden? Weil die Alternative, die du vorgeschlagen hast, klingt, wenn ich richtig verstehe, werde ich alle Python-Sessions beenden, die ich nicht machen will, weil dieses Stück in einer Kette von for-Schleifen ist. Ich will diese spezielle Session einfach beenden und zu den anderen Elementen weitergehen die for-Schleife. – jackaraz

+0

1- Ausnahmen werden im Hauptthread verbreitet. Das Problem könnte sein, dass 'func()' (aufgrund eines Fehlers) vergessen kann, 'PyErr_CheckSignal()' auf 'EINTR' in seinem C-Code aufzurufen und daher der Python-Signalhandler erst aufgerufen wird, wenn' func() 'die Kontrolle zurückgibt zum Dolmetscher. 2- Was ist der Punkt, an dem SIGTERM an den Python-Prozess gesendet wird? Offenbar möchte OP stattdessen einen Kindprozess beenden. Der Zweck von "SIGALRM" besteht darin, jeden Python-Prozess zu unterbrechen, z. B. "process.wait()". 3- wenn der Code eine Variable periodisch überprüfen kann, es sei denn, der Code ist im Thread; es ist einfacher, eine Ausnahme zu erheben – jfs