Schleifen abbruch nach gewisser Zeit

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
123GuteLaune
User
Beiträge: 27
Registriert: Mittwoch 2. November 2016, 22:35

Hallo,

ich habe einen Code geschrieben der auf ein externes Programm zugreift. Leider entsteht bei dem externen Programm ab und zu ein Fehler. Dieser Fehler lässt python warten auf ein feedback. Diese Feedback wird niemals eintretten, sprich eine endlose Schleife. :evil:

Ich würde gerne in meine For If not schleife einen Art Timer einbauen, der nach Starten der Schleife und Aufbau der Verbindung zum externen Programm anfängt zu zählen. Falls ein es länger als 8 sec dauert soll er auf der Schleife springen den If else Befehl ausführen. :idea:

Derzeit hab ich einen Index geschrieben der bestimmte Zeilen ausschließt, die den Fehler verursachen, leider dauert es jedesmal lange bis er eine neue Zeile findet die falsch ist und die muss ich händisch eingeben und das ganze von vorne starten :roll:

Wie kann man sowas umsetzen? (Ich bin Anfänger) :)

Codeteil

Code: Alles auswählen

    forbidden = [23975, 24733, 24735]
    for index, ber in enumerate(bers):
        if not(index in forbidden):
            res.append(single_r_x13(ber,fc,r,index))
        else:
            res.append([np.nan] * fc)
        print("---------%s sekunden fuer Arima %s ------" % (((time.time() - start_time)/ (index + 1)), index))
    return res#np.array([single_r_x13(ber,fc,r) for ber in bers])
Zuletzt geändert von Anonymous am Dienstag 31. Januar 2017, 09:24, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 18217
Registriert: Sonntag 21. Oktober 2012, 17:20

@123GuteLaune: Solange die Funktion single_r_x13 abgearbeitet wird, kann man nichts in der Schleife tun. Man müßte also beim Lesen vom externen Programm irgendwo in single_r_x13 einen Timeout einbauen.
123GuteLaune
User
Beiträge: 27
Registriert: Mittwoch 2. November 2016, 22:35

Ok also muss ich den Timer direkt in die Methode einbauen?
Die Methode greift auf ein Verfahren in R zurück das ich durch eine Schnittstelle in Python nutze

Leider weiß ich nicht wie man so einen Timer baut?

Code der Methode:

Code: Alles auswählen

def single_r_x13(ber,fc,r,c):
    #print data
    #r('library("seasonal")')
    try:
        print ber
        r.assign("rdata%s" % c, ber)
        #print(r("rdata%s" % c))
        ts_str = "my_ts%s <- ts(rdata%s, start=c(2012, 1), end=c(2014,12), frequency=12)" % (c,c)
        r(ts_str)
        
        r("ar%s <- seas(my_ts%s, forecast.save = 'forecasts')" % (c,c))

        r("res%s <- series(ar%s, 'forecast.forecasts')" % (c,c))

        forecast = r.get('res%s' % c)[:, 0][:fc]
        return forecast
    except:# TypeError:
        return [np.nan]*fc
Zuletzt geändert von Anonymous am Dienstag 31. Januar 2017, 11:51, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@123GuteLaune: Ich denke damit verschiebt sich das Problem nach R. Was hängt denn dort und warum?
123GuteLaune
User
Beiträge: 27
Registriert: Mittwoch 2. November 2016, 22:35

In R rufe ich ein Zeitreihenprognoseprogramm auf. R nutzt dabei ein numpy array aus python.

Programmablauf: Python schickt ein array nach R, R führt eine spezielle Prognose aus, R gibt einen Array aus, Array wird zurück gegeben an Python, Python schreibt diesen Wert in mein Dict. und speichert dies dann als CSV datai

Da ich das ganze massenhaft mache, entsteht manchmal ein Fehler bei der Prognose und das Programm gibt mir einen Fehler zurück das es nicht funktioniert. Diese Problem hab ich gelöst mit dem Except-Part.

Es gibt aber anscheinend noch einen anderen Fehler der im Prognoseprogramm selber entsteht und das Programm einfriert, ich weiß nicht wieso diese Fehler entsteht...

Deswegen wollte ich beim Aufrufen des Programms einen Timer laufen lassen, wenn python kein Feedback nach 8 sec bekommt soll er diese Prognose Terminieren und denn except Schleife oder die IF else schleife durchlaufen...

Kann man sowas einbauen und wenn ja wie?
BlackJack

@123GuteLaune: Ich würde mal sagen das geht nicht wenn das nicht bereits in irgendeiner Weise vorgesehen ist.

Ein ”nacktes” ``except`` sollte man übrigens nicht verwenden, das behandelt *alle* Ausnahmen, und es gibt nicht viel sinnvolles was man für *alle* Ausnahmen machen kann.
123GuteLaune
User
Beiträge: 27
Registriert: Mittwoch 2. November 2016, 22:35

Shit ich dachte ich kann des irgendwie erzwingen,...

Des ist echt doof! :K

Der except Befehl ist gewollt, da alle fehlerhaften Prognose gleich 0 gesetzt werden.
BlackJack

@123GuteLaune: Aber der greift bei *allen* Ausnahmen, also zum Beispiel auch bei Programmierfehlern die Du gemacht hast, bei Speicherfehlern, bei allem womit Du nicht rechnest, die dann einfach ignoriert werden, beziehungsweise als NaN-Werte zurück gegeben werden. Das will man nicht. Man sollte immer nur die konkreten Ausnahmen behandeln die man auch erwartet, denn nur bei denen kann man auch sicher sagen das die Behandlung Sinn macht, und nicht die Fehlersuche erschwert oder verhindert.
Nras
User
Beiträge: 24
Registriert: Dienstag 25. März 2014, 10:38

Moin,
man kann da meines Erachtens nach schon etwas machen. Ich würde die function einfach wrappen und mit dem @timeout-Dekorator von dieser Stackoverflow Antwort versehen. Statt dem if-else Teil mit der händisch gepflegten Liste mit den indices, würdest du dann einen try-except Teil einbauen. Salopp ausgedrückt steht dann da: "Gib mir ein Ergebnis, vielleicht wirfst du einen TimeoutError, dann setze ich das Ergebnis selbst.

Das könnte dann ungefähr so aussehen:

Code: Alles auswählen

from functools import wraps
from datetime import datetime
import errno
import os
import signal
import time
import numpy as np


class TimeoutError(Exception):
    pass

def timeout(seconds=10, error_message=os.strerror(errno.ETIME)):
    def decorator(func):
        def _handle_timeout(signum, frame):
            raise TimeoutError(error_message)

        def wrapper(*args, **kwargs):
            signal.signal(signal.SIGALRM, _handle_timeout)
            signal.alarm(seconds)
            try:
                result = func(*args, **kwargs)
            finally:
                signal.alarm(0)
            return result

        return wraps(func)(wrapper)

    return decorator

@timeout(8)
def may_timeout_single_r_x13(ber, fc, r, index):
    return single_r_x13(ber, fc, r, index)

def single_r_x13(ber, fc, r, index):
    # irgendetwas wird diese Methode schon machen. Bei Index 2 und 3 braucht sie lange.
    if index in [2, 3]:
        time.sleep(20)  # Dauert sehr lange
    return [ber + r + index] * fc  # anything

def main():
    # irgendetwas fuer fc, r und bers setzen.
    fc = 2
    r = 5
    bers = range(6)
    res = []
    for index, ber in enumerate(bers):
        start_time = datetime.utcnow()
        try:
            result = may_timeout_single_r_x13(ber, fc, r, index)
        except TimeoutError:
            print(repr(e))
            result = [np.nan] * fc
        res.append(result)
        print("---------%s sekunden fuer Arima %s ------" % (datetime.utcnow() - start_time, index))
    print(res)
    return


if __name__ == '__main__':
    main()
Das Produziert bei mir folgenden output:

Code: Alles auswählen

---------0:00:00.000018 sekunden fuer Arima 0 ------
---------0:00:00.000014 sekunden fuer Arima 1 ------
TimeoutError('Timer expired',)
---------0:00:08.000142 sekunden fuer Arima 2 ------
TimeoutError('Timer expired',)
---------0:00:08.000195 sekunden fuer Arima 3 ------
---------0:00:00.000019 sekunden fuer Arima 4 ------
---------0:00:00.000012 sekunden fuer Arima 5 ------
[[5, 5], [7, 7], [nan, nan], [nan, nan], [13, 13], [15, 15]]
BlackJack

@Nras: Von `signal`-Vodoo würde ich abraten. Das ist Unix-Systemprogrammierung die ein bis zwei Ebenen unter dem liegen was man mit Python üblicherweise macht. Es funktioniert nicht mit Threads und man muss sich darüber im klaren sein, dass das ein harter Ausstieg aus was immer gerade passiert ist. Da irgendwelche Garantien zu geben das alles in einem geordneten Zustand hinterlassen wird ist schwer. Im Falle des OP wahrscheinlich unmöglich, denn der Alarm kann ja mitten in einem Aufruf von R kommen. Wie soll man da sicherstellen, dass R und/oder die Python-Anbindung danach noch in einem ordentlichen Zustand sind? Der Code dort ist doch gar nicht darauf ausgelegt einfach so abgebrochen/unterbrochen zu werden.

Zumal das ``raise TimeoutError(error_message)`` nur greift wenn Python überhaupt die Kontrolle hat. Wenn das in R irgendwo hängt, kommt man da auch mit einer Python-Ausnahme nicht heraus.
123GuteLaune
User
Beiträge: 27
Registriert: Mittwoch 2. November 2016, 22:35

Cool vielen Dank ich werde diese Methode mit dem Signal wrapper testen!

@BlackJack:
Du hast natürlich recht, das ich das eigentlich nicht machen sollte, aber da ich mehr als 1 Mio Zeitreihen prognostiziere, muss ich leider so agieren, da ich nicht alle Fehler ausmerzen kann!
Zudem scheint R auch kein Problem zu verursachen sondern das X13as (Statistik programm von US-Staat). Ich habe da mit den Leute wegen meinen Fehler gesprochen und die meint des Programm ist so heavy das kann keiner mehr so richtig greifen! Deswegen diese etwas harte und uncoole lösung!
Konkret teste ich, ob das Programm was taugt oder nicht wenn ich nur Prognose mit "nan" bekomme ist das Entscheidung gegen so einen Ansatz!
BlackJack

@123GuteLaune: Das sollte man nicht nur *eigentlich* nicht machen, sondern das sollte man wirklich *nicht* machen. Selbst wenn es ”funktioniert” kannst Du nach dem ersten Timeout im Grunde keinen Ergebnissen mehr trauen, weil Du nicht weisst ob sich das alles noch in einem gültigen Zustand befindet.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Um BlackJack mal zu übersetzen: Dein Programm ist kaputt, da du das Signal nicht zuverlässig abfangen kannst. Wenn du eine mit timeout dekorierte Funktion aufrufst bekommst du nun entweder einen TimeoutError oder ein Ergebnis von dem du nicht ausgehen kannst dass es richtig ist.

Was du statt dessen machen könntest ist das externe Programm in einem eigenen Prozess laufen zu lassen. Du kannst dann problemlos auf ein Ergebnis warten oder ggfs. den Prozess killen. Das ist nicht wesentlich schwieriger, hat den gleichen Effekt und funktioniert garantiert.
123GuteLaune
User
Beiträge: 27
Registriert: Mittwoch 2. November 2016, 22:35

Eigentlich wäre das auch mein Wunsch gewesen, leider weiß ich nicht wie das funktioniert zwei Prozesse laufen zu lassen.

Meine Vorstellung war:
Das ich sobald ich in meine Funktion in R Aufruf gleichzeitig eine Uhr in einem anderen Prozess starte, falls das Zeitlimit überschritten wird, soll der derzeitig Prozess abgebrochen werden also ganz normal ausgeschalten. Und bei Abbruch soll für meine Zeitreihe diese except Schleife laufen.

Könntest du mir sagen wo ich sowas nachlesen kann oder mir einen Beispielhaften Code geben?

Mein Programm code gesamt anbei!

Code: Alles auswählen

import numpy as np
import pyper as pr
import time 
from csv_read import read_in

#path_folder = r'/Users/Backup/'
#data = read_in('X.csv',path_folder)[0]
#fc=18

def r_x13(bers, fc):
    r = pr.R(RCMD='/usr/local/bin/R', use_numpy=True)
    r('library("seasonal")')
    
    if not (type(bers) is np.array):
        bers = np.array(bers)
    res = []
    start_time = time.time()
    forbidden = [23975, 24733, 24735]
    for index, ber in enumerate(bers):
        if not(index in forbidden):
            res.append(single_r_x13(ber,fc,r,index))
        else:
            res.append([np.nan] * fc)
        print("---------%s sekunden fuer Arima %s ------" % (((time.time() - start_time)/ (index + 1)), index))
    return res#np.array([single_r_x13(ber,fc,r) for ber in bers])

def single_r_x13(ber,fc,r,c):

    try:
        print ber
        r.assign("rdata%s" % c, ber)
        ts_str = "my_ts%s <- ts(rdata%s, start=c(2012, 1), end=c(2014,12), frequency=12)" % (c,c)
        r(ts_str)

        r("ar%s <- seas(my_ts%s, forecast.save = 'forecasts')" % (c,c))
        r("res%s <- series(ar%s, 'forecast.forecasts')" % (c,c))
        forecast = r.get('res%s' % c)[:, 0][:fc]
        return forecast
    except:# TypeError:
        return [np.nan]*fc
Zuletzt geändert von Anonymous am Mittwoch 1. Februar 2017, 23:03, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 18217
Registriert: Sonntag 21. Oktober 2012, 17:20

@123GuteLaune: vielleicht hilft es schon die Dokumentation zu dem Modul zu lesen, das Du da benutzt:
Some errors in command strings sent to R can be fatal to PypeR!
For example, incomplete command strings, typically, missing quotes or parentheses, will lead to a dead waiting: R is waiting for more input from Python while Python is trying to getting output from R.

In Such cases, the user has to press "Ctrl - C" to break the pipe, and restart R again. So far I have no idea for a solution for this problem.
Da hilft es vielleicht schon, ein etwas ausgereifteres Paket zu benutzen, statt eins, das bald seit 3 Jahren nicht mehr weiter entwickelt wird. Was bietet denn diese csv_read mehr, was nicht numpy auch könnte?
Den Typ explizit zu prüfen, ist schlecht, da es der Objektorientierung widerspricht. In Deinem Fall ist der richtige Weg das Prüfen numpy.asanyarray zu überlassen.
123GuteLaune
User
Beiträge: 27
Registriert: Mittwoch 2. November 2016, 22:35

Hi Sirius,

ich habe eine wissenschaftliche Abhandlungen über die gängisten R inferface gelesen und dabei hat diese Modul am besten abgeschnitten. Ich ruf ja auch nur eine Methode auf der R rest läuft ja dann in R.

ich habe meine Daten überprüft sie werden richtig übergeben und es hat für andere Datein super geklappt!
Sprich R und Python sind gut zu einander!
Das Problem ist das externe Prognoseprogramm, dass ich Aufrufe durch R! Anscheinend ist im Interface von R und diesem Programm ein Problem nicht abgedeckt und R warte auf Feedback das es an Python übergeben kann.
Mehr konnte ich bis jetzt noch nicht rausfinden... Es gibt auch ein Inferface von python direkt zu diesem Programm, aber des ist noch viel älter und weitaus langsamer, deswegen kommt der für mich nicht in Betracht
http://statsmodels.sourceforge.net/0.6. ... hlight=x13

Das csv.read ist nur meine Datei, wo ich meine Zeitreihen die ich gemacht habe einlese in die entsprechende Form das R und das Programm was anfangen kann! Wie gesagt ich habe schon 600.000 Prognosen berechnet so weit so gut nur fehlen mir noch 400.000 und diese Fehler tritt nur selten auf in 25.000 Prognose waren es 3 mal.
Nras
User
Beiträge: 24
Registriert: Dienstag 25. März 2014, 10:38

Hallo,
BlackJack hat geschrieben:@123GuteLaune: Das sollte man nicht nur *eigentlich* nicht machen, sondern das sollte man wirklich *nicht* machen. Selbst wenn es ”funktioniert” kannst Du nach dem ersten Timeout im Grunde keinen Ergebnissen mehr trauen, weil Du nicht weisst ob sich das alles noch in einem gültigen Zustand befindet.
also ich benutze diesen timeout Dekorator für so einiges, mir ist nie aufgefallen, dass unplausible Werte geliefert werden, nachdem so ein TimeOut stattfand. Könnest du dafür ein simples Beispiel produzieren?

Gruß,
Nras.
Antworten