2009-09-10 13 views
5

Recientemente comencé a aprender Python y parte de la sencilla aplicación que estoy haciendo incluye un temporizador con una pantalla hh: mm: ss ejecutándose en su propio hilo.Python sched.scheduler excede la profundidad máxima de recursión

Mirando alrededor de la web me encontré con dos formas de implementar esta:

  1. Uso sched.scheduler
  2. Uso threading.Timer

La forma en que lo hice es similar para ambas implementaciones:

sched:

def tick(self, display, alarm_time): 

    # Schedule this function to run every minute 
    s = sched.scheduler(time.time, time.sleep) 
    s.enter(1, 1, self.tick, ([display, alarm_time])) 

    # Update the time 
    self.updateTime(display) 

Temporizador:

def tick(self, display): 

    # Schedule this function to run every second 
    t = Timer(1, self.tick, (display,alarm_time)) 
    t.start() 

    # Update the time 
    self.updateTime(display) 
  1. funciona bien con respecto a marcando correctamente, pero genera el siguiente error después de unos minutos: RuntimeError: máximo nivel de recursividad superó. Sé que puede aumentar el nivel máximo de recursión manualmente, pero seguramente esto no debería ser necesario aquí.

  2. No hay error, pero ocasionalmente los segundos se saltan o marcan de forma irregular.

¿Puede alguien indicarme en la dirección correcta cómo hacer esto correctamente? Gracias.

+0

Por favor, publique el enlace que encontró para usar threading.Timer como este. –

+0

El título de su pregunta es completamente incorrecto. Tiene un temporizador que excede la profundidad de recursión. No es sched.scheduler. –

+1

Lo siento si no estaba claro. Pregunta editada La sugerencia de usar el temporizador vino de aquí Tenga en cuenta que soy solo un principiante y probablemente tenga una idea equivocada. – user171331

Respuesta

4

Un temporizador es un evento único. No se puede hacer que se repita de esta manera.

Usando un temporizador para llamar a una función que luego crea otro temporizador que llama a una función que crea un temporizador que llama a una función que crea un temporizador, ..., debe alcanzar el límite de recursión.

No menciona su sistema operativo, pero la "omisión" o "tic-tac de forma irregular" se debe a dos motivos.

  1. Usted equipo está ocupado y "1 segundos" significa "bastante cercano a 1 segundo, dependiendo de lo que esté sucediendo"

  2. Si se inicia el temporizador en 0.9999 segundos, y esperar 1 segundo , es posible que esté en 1.9999 (redondea a 1) o 2.00000. Puede parecer duplicar un tiempo u omitir un tiempo. El reloj interno del hardware de su computadora es muy preciso, y redondear las cosas al segundo más cercano (siempre) dará lugar a la posibilidad remota de duplicados u omisiones.

Use sched correctamente. http://docs.python.org/library/sched.html#module-sched

Su fragmento de código tampoco tiene sentido para sched. No necesita crear un nuevo objeto del planificador. Solo necesita crear un nuevo evento .

Lea http://docs.python.org/library/sched.html#sched.scheduler.enter sobre la creación de un nuevo evento para una instancia existente del programador.

+1

Gracias por su respuesta. He aclarado la pregunta para incluir mi implementación de sched y el error, pero supongo que la razón es la misma que usted ha dado para Timer. Sin embargo, si sched programa un solo evento en una fecha posterior, todavía no veo cómo evitar el límite de recursión :( – user171331

+0

Explicación muy clara – DrFalk3n

+0

Aparte de los enlaces a las páginas de Python Doc, ¿cuál es la "dirección correcta" para ir luego :) – HongboZhu

5

A continuación, se indica cómo convertir un disparo único en un evento periódico, p.con sched: si la función tiene que hacer su propio programador y ser la única cosa que se ejecuta en su rosca:

def tick(self, display, alarm_time, scheduler=None): 
    # make a new scheduler only once & schedule this function immediately 
    if scheduler is None: 
    scheduler = sched.scheduler(time.time, time.sleep) 
    scheduler.enter(0, 1, self.tick, ([display, alarm_time, scheduler])) 
    scheduler.run() 

    # reschedule this function to run again in a minute 
    scheduler.enter(1, 1, self.tick, (display, alarm_time, scheduler])) 

    # do whatever actual work this function requires, e.g.: 
    self.updateTime(display) 

Si otros eventos también deben ser programadas en el mismo hilo entonces el planificador debe ser hecha y propiedad "en otro lugar" - la parte superior puede conseguir if reprogramado para utilizar otro método, por ejemplo:

def scheduleperiodic(self, method, *args): 
    self.scheduler = sched.scheduler(time.time, time.sleep) 
    self.scheduler.enter(0, 1, method, args) 
    # whatever else needs to be scheduled at start, if any, can go here 
    self.scheduler.run() 

def tick(self, display, alarm_time): 
    # reschedule this function to run again in a minute 
    self.scheduler.enter(60, 1, self.tick, (display, alarm_time)) 

    # do whatever actual work this function requires, e.g.: 
    self.updateTime(display) 

Una vez más, por supuesto, y como siempre con sched, mientras que el planificador está en ejecución, (y las devoluciones de llamada de eventos programados) se "hacerse cargo "el hilo en cuestión (por lo que tendrás que separar un hilo por separado si necesitas otras cosas para estar sucediendo al mismo tiempo).

Si necesita utilizar este tipo de modismo en muchas funciones, podría ser refactorizado en un decorador, pero eso enmascararía un tanto la simplicidad subyacente del modismo, por lo que prefiero este uso simple y abierto. Por cierto, tenga en cuenta que time.time y time.sleep usan segundos, no minutos, como su unidad de tiempo, por lo que necesita 60, no uno, para indicar "un minuto a partir de ahora" ;-).

+0

Seguí la sugerencia para un decorador – DrFalk3n

Cuestiones relacionadas