2011-11-23 81 views
7

我想在運行0.5秒後超時一段特定的python代碼。所以我打算在0.5秒後發出一個異常/信號,並且正常處理它並繼續處理其餘的代碼。如何在0.5秒後在python 2.4中發出警報

在python我知道signal.alarm()可以設置整數秒的警報。在0.5秒後我們可以產生報警嗎? signal.setitimer()在其他文章中建議不在python2.4中可用,我需要爲此使用python2.4?

+0

編寫C擴展是一個選項... – pajton

+1

給誰投票決定關閉這個問題支持的想法是[這一個完全相同的副本](http://stackoverflow.com/q/3770711/146792):你真的讀過OP問題直到它結束嗎?問題是完全有效的IMO。 – mac

+0

@mac:我認爲投票結束的人已經知道她的錯誤 - 至少她刪除了自動生成的評論。 :) –

回答

2

你有兩個選擇:

  1. 輪詢time.time()或在有問題的代碼運行類似。如果該代碼在您的控制之下,這是明顯可行的。

  2. 正如pajton所述,您可以編寫一個C擴展名來調用系統調用setitimer()。這並不難,因爲您可以簡單地複製源自更高版本Python的源代碼signal.getitimer()signal.setitimer()。它們僅僅是同名系統調用的簡單包裝。

    如果您使用CPython並且您處於允許使用自定義C擴展的環境中,則此選項纔可行。

    編輯:這裏是signalmodule.c in Python 2.7複製的代碼(Python的許可適用):

    #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); 
    } 
    

    這段代碼保存爲itimermodule.c,使用類似

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

    把它編譯成一個C擴展現在,如果你幸運的話,你應該可以使用

    import itimer 
    

    並致電itimer.setitimer()

+0

絕對未經測試:但如果在線程下發生信號並在主代碼中運行計時器(輪詢'time.time()'),那麼如何運行要修剪的代碼?一旦限制被擊中,計時器就可以殺死線程...... [醜陋但是...不能工作?] – mac

+0

@mac:不,這不起作用。你不能在Python中殺死線程。 –

+0

@sven:代碼不受我控制。涉及很多計算和函數調用,並且很難在一個地方進行輪詢。 –

4

提高耐心等待的「守護進程」線程的警報。在下面的代碼,snoozealarm你想要做什麼通過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

好主意,+1 .. –

+0

這就是我所說的「反向」工程。 +1;) – mac