最近寫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是另開的一個線程,所以這個異常別人獲取不到,只有在本線程裏處理纔有用,而且卡死的函數也不會停下來。