python函數執行超時後跳過

最近寫bug時遇到一個關於函數執行超時的問題,就是某一步執行時間過長,或者程序直接卡死了,找到了三種解決方法,現在敘述下,幫助需要的人。

(1)使用eventlet

參考鏈接:https://blog.csdn.net/zjshui/article/details/78874621

import time
import eventlet  #導入eventlet這個模塊
eventlet.monkey_patch()   #必須加這條代碼
with eventlet.Timeout(2,False):   #設置超時時間爲2秒
   print '這條語句正常執行'
   time.sleep(4)
   print '沒有跳過這條輸出'
print '跳過了輸出'

 使用eventlet的好處是在於可以真對某一步的進行限制,尤其是在寫爬蟲的時候有很大的益處。

但是eventlet也存在一定的問題,就是針對子進程無法跳出。如下面這個代碼就有問題。

import time
import eventlet
import os
eventlet.monkey_patch()   #必須加這條代碼
with eventlet.Timeout(20,False):   #設置超時時間爲20秒
   print '這條語句正常執行'
   cmd1 = 'binwalk -B {0}'.format(filename)
   info1_lines = os.popen(cmd1).readlines()
   cmd2 = 'file {0}'.format(filename)
   info2_lines = os.popen(cmd2).readlines()
   print '沒有跳過這條輸出'
print '跳過了輸出'

我的目的是防止程序卡死,所以加了eventlet,但是在我使用的時候還是存在卡死的情況,當時就很鬱悶,不是已經加了時間限制嗎,爲什麼還是不能夠跳出。然後發現問題出在了os模塊,一直卡在此步,不能夠跳出,調用了子進程。

(2)使用signal設置裝飾器

參考鏈接:https://www.cnblogs.com/buxizhizhoum/p/7113355.html

https://www.jb51.net/article/159375.htm

https://www.cnblogs.com/lyxdw/p/10033118.html

廢話不多說,上代碼,看下代碼就很請出了,比說得更清楚。

import signal

def time_limit(set_time,callback):
'''set_time是設置的時間限制,callback是程序運行後執行的函數'''
    def wraps(func):
# 收到信號SIGALRM後的回調函數,參數1是信號的數字,參數2是the interrupted stack frame.
        def handler(signum, frame):
            raise RuntimeError()
        def deco(*args, **kwargs):
            signal.signal(signal.SIGALRM, handler)
            signal.alarm(set_time)
            res = func(*args, **kwargs)
            signal.alarm(0)
            return res
         except RuntimeError as e:
            callback()  ##如果不想要超時跳轉,那麼直接刪除callback()和對應的參數
            #print e.message
        return deco
    return wraps


def after_timeout(): # 超時後的處理函數
  print("Time out!")
  return

@set_timeout(2, after_timeout)  # 限時 2 秒超時
def connect():  # 要執行的函數
    a = 1
    b=2
    time.sleep(3)  # 函數執行時間,寫大於2的值,可測試超時
    print “完成” 
    return a,b


if __name__ == '__main__':
    print "test"  #此句正常執行輸出
    if time_limite() != None  ##如果超時,此步a爲None,否則爲
        a,b = connet()
        print a   ##正常輸出
        print b   ##正常輸出
    c = 4
    print c  ##此步正常輸出
    

最後我採用了此種裝飾器的方法進行了處理。

當然也可以直接設置超時退出,那就需要將callback函數和參數就可以了。

(3)使用threading

https://www.cnblogs.com/lyxdw/p/10033118.html 

from threading import timer

def time_limit(interval):
    def wraps(func):
        def time_out():
            raise RuntimeError()

        def deco(*args, **kwargs):
            timer = Timer(interval, time_out)
            timer.start()
            res = func(*args, **kwargs)
            timer.cancel()
            return res
        return deco
    return wraps

使用方式,在需要監控的函數上寫@time_limit(5),即可定時5秒報錯.經過測試,覺得沒什麼用。粗略看來,運行一下確實在程序超過interval規定的時間後拋出了RuntimeError。但是由於timer是另開的一個線程,所以這個異常別人獲取不到,只有在本線程裏處理纔有用,而且卡死的函數也不會停下來。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章