1. 程式人生 > >Python使用裝飾器和執行緒限制函式執行時間的方法

Python使用裝飾器和執行緒限制函式執行時間的方法

前言:

  (不想看廢話的可以直接copy尾部的程式碼)   在八月上旬的時候,曾經寫過一個多執行緒爬蟲。程式在執行時經常莫名的卡死。這令我很是費解,後來才發現,是在請求對方資源時,伺服器長時間未返回完資料。導致IO阻塞。   其實不只是爬蟲,很多時候一個函式很可能因為某種不可預知的事情,而有時很可能會卡在某一處,繼而函式無法繼續執行下去。導致擁塞。   此時,我們自然而然的會想到如果能寫一個裝飾器來限制一個函式執行的時間,那麼問題也就迎刃而解了。

正文:

  最初,因為我的擁塞是發生在多程序中,我曾經想通過殺死執行緒的方式來解決問題。然而python中的threading模組中並沒有提供這一方法。網上有類似方法,但是比較繁瑣。並且非常不建議直接殺死執行緒(這其中可能關係到資源釋放的問題,比如我從佇列中取出了一個url, 然而我的程序卡死了,並沒有完成相應的任務,我卻強行得終止了這個執行緒,url中的內容未採集,url也沒用放回到佇列中,豈不是造成了資源的浪費)。後來想到可以直接對函式的執行時間進行限制,這樣就省了不少事情。

方法一:

  此方法比較容易理解,寫了一個裝飾器,看到其中的__wrapper函式,新建了一個守護執行緒,target是我們需要限制時間的函式。啟動守護執行緒之後,主執行緒sleep(timer)(timer就是我們設定的函式執行時間)。若在規定的執行時間未結束守護程序(也就是我們需要限制執行時間的函式),則主動丟擲異常。(但此種方法有一個弊端,就是如果函式在目標時間內執行完了,由於sleep的原因,整個執行緒還是會等到sleep(timer)後結束,可能會浪費時間)

#!/usr/bin/env python
#-*- coding:utf-8 -*- 
#Author: Chen
import
threading import time def time_limited(timer): ''' 一個規定函式執行時間的裝飾器 :param timer: :return: ''' def wrapper(func): def __wrapper(params): start_time = time.time() #通過設定守護執行緒強制規定函式的執行時間 t = threading.Thread(target=func, args=params) t.setDaemon(True
) t.start() time.sleep(timer) if t.is_alive(): #若在規定的執行時間未結束守護程序,則主動丟擲異常 raise Exception('Function execution timeout') #print time.time()-start_time return __wrapper return wrapper

第二種:

  此種方法是第一種的升級,改進了函式執行完不結束的弊端

#!/usr/bin/env python
#-*- coding:utf-8 -*- 
#Author: Chen
import time
from threading import Thread

ThreadStop = Thread._Thread__stop#獲取私有函式
def time_limited_pri(time_limited):
    def wrapper(func):
        def __wrapper(params):
            class TimeLimited(Thread):
                def __init__(self):
                    Thread.__init__(self)
                def run(self):
                    func(params)
                def _stop(self):
                    if self.is_alive():
                        ThreadStop(self)
                        raise Exception('Function execution overtime')
            t = TimeLimited()
            t.start()
            t.join(timeout=time_limited)
            if t.is_alive():
                t._stop()
                raise Exception('Function execution overtime')
        return __wrapper
    return wrapper