2011-11-23 9 views
7

Quiero esperar el tiempo de una pieza particular del código de Python en ejecuciones durante 0.5 segundos. Así que tengo la intención de levantar una excepción/señal después de 0.5 segundos, manejarla con gracia y continuar con el resto del código.Cómo señalar la alarma en Python 2.4 después de 0.5 segundos

En python sé que signal.alarm() puede configurar la alarma para segundos enteros. ¿Hay alguna alternativa donde podamos generar una alarma después de 0.5 segundos? signal.setitimer() como se sugiere en otras publicaciones no está disponible en python2.4 y necesito usar python2.4 para este propósito?

+0

escribir una extensión C es una opción ... – pajton

+1

A quien votó para cerrar esta pregunta apoyando la idea es un duplicado exacto de [éste ] (http://stackoverflow.com/q/3770711/146792): ¿has leído la pregunta OP hasta su final? La pregunta es completamente válida IMO. – mac

+0

@mac: Creo que la persona que votó para cerrar ya descubrió su error, al menos eliminó el comentario generado automáticamente. :) –

Respuesta

2

tiene dos opciones:

  1. de votación time.time() o similares, mientras que el código en cuestión se ejecuta. Obviamente, esto solo es viable si ese código está bajo su control.

  2. Según lo mencionado por pajton, podría escribir una extensión C para llamar al sistema llame al setitimer(). Esto no es demasiado difícil porque simplemente puede copiar el código de signal.getitimer() y signal.setitimer() de la fuente de las versiones posteriores de Python. Son solo envoltorios delgados sobre las llamadas al sistema igualmente nombradas.

    Esta opción solo es viable si usa CPython y se encuentra en un entorno que le permite usar extensiones C personalizadas.

    Editar: Aquí está el código copiado de signalmodule.c in Python 2.7 (licencia de Python aplica):

    #include "Python.h" 
    #include <sys/time.h> 
    
    static PyObject *ItimerError; 
    
    /* auxiliary functions for setitimer/getitimer */ 
    static void 
    timeval_from_double(double d, struct timeval *tv) 
    { 
        tv->tv_sec = floor(d); 
        tv->tv_usec = fmod(d, 1.0) * 1000000.0; 
    } 
    
    Py_LOCAL_INLINE(double) 
    double_from_timeval(struct timeval *tv) 
    { 
        return tv->tv_sec + (double)(tv->tv_usec/1000000.0); 
    } 
    
    static PyObject * 
    itimer_retval(struct itimerval *iv) 
    { 
        PyObject *r, *v; 
    
        r = PyTuple_New(2); 
        if (r == NULL) 
        return NULL; 
    
        if(!(v = PyFloat_FromDouble(double_from_timeval(&iv->it_value)))) { 
        Py_DECREF(r); 
        return NULL; 
        } 
    
        PyTuple_SET_ITEM(r, 0, v); 
    
        if(!(v = PyFloat_FromDouble(double_from_timeval(&iv->it_interval)))) { 
        Py_DECREF(r); 
        return NULL; 
        } 
    
        PyTuple_SET_ITEM(r, 1, v); 
    
        return r; 
    } 
    
    static PyObject * 
    itimer_setitimer(PyObject *self, PyObject *args) 
    { 
        double first; 
        double interval = 0; 
        int which; 
        struct itimerval new, old; 
    
        if(!PyArg_ParseTuple(args, "id|d:setitimer", &which, &first, &interval)) 
        return NULL; 
    
        timeval_from_double(first, &new.it_value); 
        timeval_from_double(interval, &new.it_interval); 
        /* Let OS check "which" value */ 
        if (setitimer(which, &new, &old) != 0) { 
        PyErr_SetFromErrno(ItimerError); 
        return NULL; 
        } 
    
        return itimer_retval(&old); 
    } 
    
    PyDoc_STRVAR(setitimer_doc, 
    "setitimer(which, seconds[, interval])\n\ 
    \n\ 
    Sets given itimer (one of ITIMER_REAL, ITIMER_VIRTUAL\n\ 
    or ITIMER_PROF) to fire after value seconds and after\n\ 
    that every interval seconds.\n\ 
    The itimer can be cleared by setting seconds to zero.\n\ 
    \n\ 
    Returns old values as a tuple: (delay, interval)."); 
    
    static PyObject * 
    itimer_getitimer(PyObject *self, PyObject *args) 
    { 
        int which; 
        struct itimerval old; 
    
        if (!PyArg_ParseTuple(args, "i:getitimer", &which)) 
        return NULL; 
    
        if (getitimer(which, &old) != 0) { 
        PyErr_SetFromErrno(ItimerError); 
        return NULL; 
        } 
    
        return itimer_retval(&old); 
    } 
    
    PyDoc_STRVAR(getitimer_doc, 
    "getitimer(which)\n\ 
    \n\ 
    Returns current value of given itimer."); 
    
    static PyMethodDef itimer_methods[] = { 
        {"setitimer",  itimer_setitimer, METH_VARARGS, setitimer_doc}, 
        {"getitimer",  itimer_getitimer, METH_VARARGS, getitimer_doc}, 
        {NULL,      NULL}   /* sentinel */ 
    }; 
    
    PyMODINIT_FUNC 
    inititimer(void) 
    { 
        PyObject *m, *d, *x; 
        int i; 
        m = Py_InitModule3("itimer", itimer_methods, 0); 
        if (m == NULL) 
         return; 
    
        d = PyModule_GetDict(m); 
    
    #ifdef ITIMER_REAL 
        x = PyLong_FromLong(ITIMER_REAL); 
        PyDict_SetItemString(d, "ITIMER_REAL", x); 
        Py_DECREF(x); 
    #endif 
    #ifdef ITIMER_VIRTUAL 
        x = PyLong_FromLong(ITIMER_VIRTUAL); 
        PyDict_SetItemString(d, "ITIMER_VIRTUAL", x); 
        Py_DECREF(x); 
    #endif 
    #ifdef ITIMER_PROF 
        x = PyLong_FromLong(ITIMER_PROF); 
        PyDict_SetItemString(d, "ITIMER_PROF", x); 
        Py_DECREF(x); 
    #endif 
    
        ItimerError = PyErr_NewException("itimer.ItimerError", 
                PyExc_IOError, NULL); 
        if (ItimerError != NULL) 
         PyDict_SetItemString(d, "ItimerError", ItimerError); 
    } 
    

    Guardar este código como itimermodule.c, compilarlo a una extensión C usando algo como

    gcc -I /usr/include/python2.4 -fPIC -o itimermodule.o -c itimermodule.c 
    gcc -shared -o itimer.so itimermodule.o -lpython2.4 
    

    Ahora, si tienes suerte, deberías poder importar esto de Python usando

    import itimer 
    

    y llame al itimer.setitimer().

+0

Absolutamente no probado: ¿pero qué hay de ejecutar el código para ser borrado si la señal ocurre bajo un hilo, y ejecutar un temporizador (sondeo 'time.time()') en el código principal? El temporizador podría matar el hilo una vez que se alcanza el límite ... [feo pero ... ¿podría funcionar?] – mac

+0

@mac: No, esto no funciona. No puedes matar hilos en Python. –

+0

@sven: el código no estará bajo mi control. Hay muchos cálculos y llamadas de función involucradas, y es difícil de sondear en un solo lugar. –

4

dar la alarma a partir de un "daemon" esperando pacientemente hilo. En el siguiente código, snoozealarm hace lo que quiere a través de un hilo SnoozeAlarm:

#! /usr/bin/env python 

import os 
import signal 
import threading 
import time 

class SnoozeAlarm(threading.Thread): 
    def __init__(self, zzz): 
    threading.Thread.__init__(self) 
    self.setDaemon(True) 
    self.zzz = zzz 

    def run(self): 
    time.sleep(self.zzz) 
    os.kill(os.getpid(), signal.SIGALRM) 

def snoozealarm(i): 
    SnoozeAlarm(i).start() 

def main(): 
    snoozealarm(0.5) 
    while True: 
    time.sleep(0.05) 
    print time.time() 


if __name__ == '__main__': 
    main() 
+0

Buena idea, +1 .. –

+0

Eso es lo que llamo ingeniería "inversa". +1;) – mac

Cuestiones relacionadas