python函數超時情況應對總結


最近處理一個線程中的函數超時問題.

函數里面有一個地方可能會卡死,我們需要去判斷這個是不是卡死了,並做出相應的應對方案.

最開始想的是在函數上增加一個裝飾器,使其在超時時拋出異常,然后在其他地方捕獲這個異常,並處理.

查詢了一些前人的方案,寫出的結果有兩種.

方案一:使用threading的timer定時器,代碼如下:

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是另開的一個線程,所以這個異常別人獲取不到,只有在本線程里處理才有用.

而且卡死的函數也不會停下來.

這種處理方式僅僅適用於一些函數與定時並不密切的時候,只是在函數超時時需要做一些動作的情況.

方案二:使用signal信號量機制,代碼如下:

 
         
import signal
def time_limit(interval): def wraps(func): def handler(): raise RuntimeError() def deco(*args, **kwargs): signal.signal(signal.SIGALRM, handler) signal.alarm(interval) res = func(*args, **kwargs) signal.alarm(0) return res return deco return wraps

可以看出來,代碼基本一樣.但是原理大不相同.運行的結果也不一樣,這段代碼裝飾需要定時的函數,在函數運行超時之后會拋出異常,停止程序.

一般情況下,這個裝飾器就夠用了.與之相同的方案,還有python的timeout模塊,

可以直接pip install timeout,然后from timeout import timeout,在需要的函數前@timeout(n)即可.

這個方案已經很不錯了,然而在實際應用中,由於是多線程,而signal不能在子線程中使用,所以否認了這個方案.

比較簡單的裝飾器想法否定掉了,就想了一些其他的辦法.

1.定時檢測線程是否alive----------卡死的線程只是不動,還是alive的

2.由於函數是生產者,可以通過計算時間,一定時間沒有新的產出,則判定這個函數卡死,然后殺掉這個線程,重開一個----------python不支持殺掉線程

3.在線程里面增加標志位,檢測標志位改變則退出循環----------天真的想法

4.改變線程為可接受stop的線程----------卡住不動收不到信號的,除非是進程

提出一些方案發現可行性都很低,最后也沒有完全解決卡死的問題.

雖然這一個線程卡死並不會影響整個程序往下走,但是不生產,又占據資源不合理.

覺得否認了這些方案以后,最干脆的辦法是檢測到這個卡死之后,手動或自動殺掉其父進程.重啟服務.

還有較不優雅的辦法,由於卡死的情況不會很多,就記錄下來,然后新開一個線程替代它的工作,直到記錄隊列滿了,給一個信號要求重啟服務.

重啟服務影響較大,不建議隨便重啟.

總的說下來,還是沒有較好的方案解決線程卡死的問題,畢竟函數卡死了就是卡死了,沒法走下去,而且在線程里面又沒法外界停下來.

先做一個記錄吧!在繼續學習的路上,希望有好的辦法.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM