2011-11-23 19 views
7

Tôi muốn hết thời gian chờ một đoạn mã python cụ thể sau khi chạy trong 0,5 giây. Vì vậy, tôi có ý định nâng cao một ngoại lệ/tín hiệu sau 0,5 giây, và xử lý nó một cách duyên dáng và tiếp tục với phần còn lại của mã.Cách báo hiệu cảnh báo trong python 2.4 sau 0.5 giây

Trong trăn tôi biết rằng signal.alarm() có thể đặt báo thức cho số nguyên giây. Có cách nào khác để chúng tôi có thể tạo báo thức sau 0,5 giây không. signal.setitimer() như đề xuất trong bài viết khác không có sẵn trong python2.4 và tôi cần phải sử dụng python2.4 cho mục đích này?

+0

viết một phần mở rộng C là một lựa chọn ... – pajton

+1

Để ai bình chọn để đóng câu hỏi này hỗ trợ các ý tưởng được một bản sao chính xác của [này ] (http://stackoverflow.com/q/3770711/146792): bạn có thực sự đọc câu hỏi OP cho đến khi kết thúc không? Câu hỏi là IMO hợp lệ hoàn toàn. – mac

+0

@mac: Tôi nghĩ người đã bỏ phiếu để đóng đã tìm ra lỗi của cô ấy - ít nhất cô ấy đã xóa nhận xét được tạo tự động. :) –

Trả lời

2

Bạn có hai lựa chọn:

  1. Polling time.time() hoặc tương tự trong khi các mã trong câu hỏi chạy. Điều này là obviuosly chỉ khả thi nếu mã đó là dưới sự kiểm soát của bạn.

  2. Như đã đề cập bởi pajton, bạn có thể viết phần mở rộng C để gọi hệ thống gọi setitimer(). Điều này không quá khó vì bạn có thể chỉ cần sao chép mã số signal.getitimer()signal.setitimer() từ nguồn của các phiên bản sau của Python. Chúng chỉ là các trình bao bọc mỏng xung quanh các cuộc gọi hệ thống được đặt tên giống nhau.

    Tùy chọn này chỉ khả thi nếu bạn đang sử dụng CPython và bạn đang ở trong một môi trường cho phép bạn sử dụng tiện ích mở rộng tùy chỉnh C.

    Sửa: Đây là mã sao chép từ signalmodule.c in Python 2.7 (giấy phép của Python áp dụng):

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

    Lưu mã này như itimermodule.c, biên dịch nó thành một phần mở rộng C sử dụng một cái gì đó giống như

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

    Bây giờ, nếu bạn may mắn, bạn sẽ có thể nhập từ Python bằng cách sử dụng

    import itimer 
    

    và gọi itimer.setitimer().

+0

Hoàn toàn chưa được kiểm tra: nhưng điều gì về việc chạy mã sẽ bị cắt xén nếu tín hiệu xảy ra dưới một chuỗi và chạy bộ đếm thời gian (bỏ phiếu 'time.time()') trong mã chính? Bộ đếm thời gian có thể giết chết sợi chỉ khi giới hạn bị trúng ... [xấu xí nhưng ... nó có thể hoạt động không?] – mac

+0

@mac: Không, điều này không hiệu quả. Bạn không thể giết các luồng trong Python. –

+0

@sven: mã sẽ không nằm trong tầm kiểm soát của tôi. Có rất nhiều tính toán và chức năng gọi điện thoại liên quan, và rất khó để thăm dò ý kiến ​​tại một nơi duy nhất. –

4

Tăng báo thức từ chuỗi "daemon" kiên nhẫn chờ đợi. Trong đoạn mã dưới đây, snoozealarm làm những gì bạn muốn thông qua một sợi 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

Ý tưởng hay, +1 .. –

+0

Đó là những gì tôi gọi là kỹ thuật "đảo ngược". +1;) – mac