2012-04-14 13 views
17

Devo eseguire un programma in python che deve essere eseguito per un po 'di tempo e quindi (non importa dove era in esecuzione) deve scaricare informazioni su un file, chiudi il file e quindi esci.Rimandare il codice per l'esecuzione successiva in python (come setTimeout in javascript)

Il comportamento qui è equivalente in JavaScript all'utilizzo di setTimeout(func, 1000000) dove il suo primo parametro (func) sarebbe un puntatore alla funzione con il codice di uscita e il suo secondo parametro sarebbe il tempo disponibile per il programma da eseguire.

so come fare questo programma in C (utilizzando SO segnali), ma con pitone

+0

Questo non è ciò che 'setTimeout' fa in JavaScript. Quello che fa è mettere in coda una funzione per l'esecuzione successiva (cioè una volta scaduto il timeout). –

+1

Sì ... Hai ragione. Ma volevo solo dare l'idea di quello che volevo, non ho trovato il bisogno di essere completamente tecnicamente corretto. – brunoais

+0

La cosa migliore che potresti fare è prendere in giro qualcosa con i fili. –

risposta

34

In pratica, uno Timer è probabilmente il modo più semplice per fare ciò che vuoi.

Questo codice farà il seguente:

  • Dopo 1 secondo, esso stampa "arg1 arg2"
  • Dopo 2 secondi, esso stampa "gufi Gufi Gufi"

===

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() 

===

Il codice precedente molto probabilmente risolverà il tuo problema.

Ma! C'è un modo alternativo, che non usa il multithreading. Funziona molto più come Javascript, che è single-threaded.

Per questa versione a thread singolo, tutto ciò che dovete fare è memorizzare la funzione ei suoi argomenti in un oggetto, insieme al momento in cui la funzione deve essere eseguita.

Una volta che l'oggetto contiene la chiamata di funzione e il timeout, controllare periodicamente se la funzione è pronta per l'esecuzione.

Il modo giusto per fare ciò è creare un priority queue per memorizzare tutte le funzioni che vogliamo eseguire in futuro, come mostrato nel codice qui sotto.

Proprio come in Javascript, questo approccio non garantisce che la funzione verrà eseguita esattamente in tempo. Una funzione che richiede molto tempo per l'esecuzione ritarderà le funzioni dopo di essa. Ma garantisce che una funzione verrà eseguita non prima del rispetto al timeout.

Questo codice farà il seguente:

  • Dopo 1 secondo, esso stampa "20"
  • Dopo 2 secondi, viene stampato "132"
  • Dopo 3 secondi, si chiude.

===

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() 

===

In pratica, si sarebbe probabilmente hanno più in corso in quel ciclo while non solo di verificare se le funzioni di timeout sono pronti ad andare. È possibile eseguire il polling per l'input dell'utente, controllare alcuni componenti hardware, leggere dati, ecc.

11

È possibile utilizzare i segnali in pitone, nonché (solo 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

Qualcosa è compatibile con Windows e Linux? (Ne ho bisogno compatibile con entrambi) – brunoais

+5

Nessuna idea. Forse qualcosa come http://docs.python.org/library/threading.html#timer-objects. – georg

+2

@ thg435 Ho provato. Il commento sopra dovrebbe essere la risposta accettata. –

Problemi correlati