8

I want to timeout a particular piece of python code after in runs for 0.5 seconds. So I intend to raise an exception/signal after 0.5 seconds, and handle it gracefully and continue with rest of code.

In python i know that signal.alarm() can set alarm for integer seconds. Is there any alternative where we can generate an alarm after 0.5 seconds. signal.setitimer() as suggested in other posts is not available in python2.4 and I need to use python2.4 for this purpose?

4

2 回答 2

5

从耐心等待的“守护进程”线程发出警报。在下面的代码中,通过线程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()
于 2011-11-23T20:39:05.133 回答
2

你有两个选择:

  1. 在有问题的代码运行时进行轮询time.time()或类似操作。这显然只有在您控制该代码时才可行。

  2. 正如pajton 所提到的,您可以编写一个C 扩展来调用系统调用setitimer()。这并不难,因为您可以简单地复制更高版本 Python 的源代码signal.getitimer()和源代码。signal.setitimer()它们只是对同名系统调用的薄包装。

    此选项仅在您使用 CPython 并且您所在的环境允许您使用自定义 C 扩展时才可行。

    编辑:这是从signalmodule.cPython 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,使用类似的东西将其编译为 C 扩展

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

    现在,如果你幸运的话,你应该可以使用 Python 从 Python 中导入它

    import itimer
    

    并打电话itimer.setitimer()

于 2011-11-23T13:18:12.077 回答