我想让一段特定的python代码在in运行0.5秒后超时。因此,我打算在0.5秒后引发一个异常/信号,并优雅地处理它,然后继续执行其余的代码。
在python中,我知道signal.alarm()
可以设置整秒的警报。有没有其他选择,我们可以在0.5秒后发出警报。其他帖子中建议的signal.setitimer()
在python2.4中不可用,我需要使用python2.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()
您有两个选项:
-
在有问题的代码运行时轮询
time.time()
或类似程序。显而易见,只有当代码在您的控制之下时,这才是可行的。 -
正如pajton所提到的,您可以编写一个C扩展来调用系统调用
setitimer()
。这并不太难,因为您可以简单地从以后版本的Python源代码中复制signal.getitimer()
和signal.setitimer()
的代码。它们只是名称相同的系统调用的薄包装。只有当您使用CPython并且您所在的环境允许您使用自定义C扩展时,此选项才可行。
编辑:以下是从Python 2.7中的
signalmodule.c
复制的代码(适用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_VIRTUALn or ITIMER_PROF) to fire after value seconds and aftern 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
,使用类似的东西将其编译为C扩展gcc -I /usr/include/python2.4 -fPIC -o itimermodule.o -c itimermodule.c gcc -shared -o itimer.so itimermodule.o -lpython2.4
现在,如果你幸运的话,你应该能够使用从Python导入它
import itimer
并呼叫CCD_ 11。