2012-04-14 10 views
17

Tengo que hacer un programa en python que necesita ejecutarse durante un tiempo y luego (no importa dónde se estaba ejecutando) debe volcar información en un archivo, cierra el archivo y luego sal.Posponer código para ejecución posterior en python (como setTimeout en javascript)

El comportamiento aquí es equivalente en JavaScript al uso de setTimeout(func, 1000000), donde su primer parámetro (func) sería un puntero a la función con el código de salida y su segundo parámetro sería el tiempo disponible para ejecutar el programa.

que saben cómo hacer este programa en C (usando así que las señales), pero con el pitón

+0

Eso no es lo que 'setTimeout' hace en JavaScript. Lo que hace es poner en cola una función para su ejecución más tarde (es decir, una vez que expira el tiempo de espera). –

+1

Sí ... Tienes razón. Pero solo quería dar la idea de lo que quería, no encontré la necesidad de ser completamente correcto desde el punto de vista técnico. – brunoais

+0

Lo mejor que puedes hacer es simular algo con los hilos. –

Respuesta

34

En la práctica, un Timer es probablemente la forma más sencilla de hacer lo que desee.

Este código hará lo siguiente:

  • Después de 1 segundo, se imprime "arg2 arg1"
  • Después de 2 segundos, se imprime "búhos" BÚHOS BÚHOS

===

from threading import Timer 

def twoArgs(arg1,arg2): 
    print arg1 
    print arg2 
    print "" 

def nArgs(*args): 
    for each in args: 
     print each 

#arguments: 
#how long to wait (in seconds), 
#what function to call, 
#what gets passed in 
r = Timer(1.0, twoArgs, ("arg1","arg2")) 
s = Timer(2.0, nArgs, ("OWLS","OWLS","OWLS")) 

r.start() 
s.start() 

===

El código anterior muy probablemente resolverá su problema.

¡Pero! Hay una manera alternativa, que no usa multihilo. Funciona mucho más como Javascript, que tiene un único subproceso.

Para esta versión de un solo hilo, todo lo que necesita hacer es almacenar la función y sus argumentos en un objeto, junto con la hora en que se debe ejecutar la función.

Una vez que tenga el objeto que contiene la llamada de función y el tiempo de espera, simplemente compruebe periódicamente si la función está lista para ejecutarse.

La forma correcta de hacer esto es haciendo un priority queue para almacenar todas las funciones que queremos ejecutar en el futuro, como se muestra en el siguiente código.

Al igual que en Javascript, este enfoque no garantiza que la función se ejecutará exactamente a tiempo. Una función que tarda mucho tiempo en ejecutarse retrasará las funciones posteriores. Pero sí garantiza que se ejecutará una función tan pronto como que su tiempo de espera.

Este código hará lo siguiente:

  • Después de 1 segundo, se imprime "20"
  • Después de 2 segundos, se imprime "132"
  • Después de 3 segundos, se cierra.

===

from datetime import datetime, timedelta 
import heapq 

# just holds a function, its arguments, and when we want it to execute. 
class TimeoutFunction: 
    def __init__(self, function, timeout, *args): 
     self.function = function 
     self.args = args 
     self.startTime = datetime.now() + timedelta(0,0,0,timeout) 

    def execute(self): 
     self.function(*self.args) 

# A "todo" list for all the TimeoutFunctions we want to execute in the future 
# They are sorted in the order they should be executed, thanks to heapq 
class TodoList: 
    def __init__(self): 
     self.todo = [] 

    def addToList(self, tFunction): 
     heapq.heappush(self.todo, (tFunction.startTime, tFunction)) 

    def executeReadyFunctions(self): 
     if len(self.todo) > 0: 
      tFunction = heapq.heappop(self.todo)[1] 
      while tFunction and datetime.now() > tFunction.startTime: 
       #execute all the functions that are ready 
       tFunction.execute() 
       if len(self.todo) > 0: 
        tFunction = heapq.heappop(self.todo)[1] 
       else: 
        tFunction = None      
      if tFunction: 
       #this one's not ready yet, push it back on 
       heapq.heappush(self.todo, (tFunction.startTime, tFunction)) 

def singleArgFunction(x): 
    print str(x) 

def multiArgFunction(x, y): 
    #Demonstration of passing multiple-argument functions 
    print str(x*y) 

# Make some TimeoutFunction objects 
# timeout is in milliseconds 
a = TimeoutFunction(singleArgFunction, 1000, 20) 
b = TimeoutFunction(multiArgFunction, 2000, *(11,12)) 
c = TimeoutFunction(quit, 3000, None) 

todoList = TodoList() 
todoList.addToList(a) 
todoList.addToList(b) 
todoList.addToList(c) 

while True: 
    todoList.executeReadyFunctions() 

===

En la práctica, es probable que hayan más en juego en ese bucle, mientras que sólo comprobar si sus funciones de tiempo de espera están listos para ir. Es posible que esté sondeando para la entrada del usuario, controle algún hardware, lea datos, etc.

11

Usted puede usar señales en Python, así (sólo UNIX)

import signal, sys 

# install a SIGALRM handler 

def handler(signum, frame): 
    print "got signal, exiting" 
    sys.exit(1) 

signal.signal(signal.SIGALRM, handler) 

# emit SIGALRM after 5 secs 

signal.setitimer(signal.ITIMER_REAL, 5) 

# do stuff 

i = 1 
while True: 
    if i % 100000 == 0: 
     print i 
    i += 1 

Docs: http://docs.python.org/library/signal.html

+0

¿Algo compatible con Windows y Linux? (Lo necesito compatible con ambos) – brunoais

+5

No tengo idea. Algo como http://docs.python.org/library/threading.html#timer-objects quizás. – georg

+2

@ thg435 He probado. El comentario anterior debe ser la respuesta aceptada. –

Cuestiones relacionadas