Python控制函數運行時間


      在某個Flask項目在做后端接口時需要設置超時響應,因為接口中使用爬蟲請求了多個網站,響應時間時長時短。

      需要設置一個最大響應時間,時間內如果接口爬蟲沒跑完,直接返回請求超時。

方法1:使用線程控制

import requests, datetime, time
import threading


class MyThread(threading.Thread):
    def __init__(self, target, args=()):
        """
        why: 因為threading類沒有返回值,因此在此處重新定義MyThread類,使線程擁有返回值
        此方法來源 https://www.cnblogs.com/hujq1029/p/7219163.html?utm_source=itdadao&utm_medium=referral
        """
        super(MyThread, self).__init__()
        self.func = target
        self.args = args

    def run(self):
        # 接受返回值
        self.result = self.func(*self.args)

    def get_result(self):
        # 線程不結束,返回值為None
        try:
            return self.result
        except Exception:
            return None


# 為了限制真實請求時間或函數執行時間的裝飾器
def limit_decor(limit_time):
    """
    :param limit_time: 設置最大允許執行時長,單位:秒
    :return: 未超時返回被裝飾函數返回值,超時則返回 None
    """

    def functions(func):
        # 執行操作
        def run(*params):
            thre_func = MyThread(target=func, args=params)
            # 主線程結束(超出時長),則線程方法結束
            thre_func.setDaemon(True)
            thre_func.start()
            # 計算分段沉睡次數
            sleep_num = int(limit_time // 1)
            sleep_nums = round(limit_time % 1, 1)
            # 多次短暫沉睡並嘗試獲取返回值
            for i in range(sleep_num):
                time.sleep(1)
                infor = thre_func.get_result()
                if infor:
                    return infor
            time.sleep(sleep_nums)
            # 最終返回值(不論線程是否已結束)
            if thre_func.get_result():
                return thre_func.get_result()
            else:
                return"請求超時"  #超時返回  可以自定義

        return run

    return functions

#接口函數
def a1():
    print("開始請求接口")

    #這里把邏輯封裝成一個函數,使用線程調用
    a_theadiing = MyThread(target=a2)
    a_theadiing.start()
    a_theadiing.join()

    #返回結果
    a = a_theadiing.get_result()

    print("請求完成")
    return a
@limit_decor(3)   #超時設置為3s   2s邏輯未執行完畢返回接口超時
def a2():
    print("開始執行")
    time.sleep(2)
    print("執行完成")
    a=2
    return a

# 程序入口     未超時返回a的值   超時返回請求超時
if __name__ == '__main__':
    a = a1()  #調用接口(這里把函數a1看做一個接口)
    print(a)

超時設置3s,線程調用函數運行2s,這里返回a的值2。

 

方法2:使用信號模塊signal(只能在unix系統使用)

signal負責在Python程序內部處理信號,典型的操作包括預設信號處理函數,暫停並等待信號,以及定時發出SIGALRM等。

要注意,signal包主要是針對UNIX平台(比如Linux, MAC OS),而Windows內核中由於對信號機制的支持不充分,所以在Windows上的Python不能發揮信號系統的功能。

信號是進程之間通訊的方式,是一種軟件中斷。一個進程一旦接收到信號就會打斷原來的程序執行流程來處理信號。

復制代碼
def set_timeout(num):
    def wrap(func):
        def handle(signum, frame):  # 收到信號 SIGALRM 后的回調函數,第一個參數是信號的數字,第二個參數是the interrupted stack frame.
            raise RuntimeError

        def to_do(*args):
            try:
                signal.signal(signal.SIGALRM, handle)  # 設置信號和回調函數
                signal.alarm(num)  # 設置 num 秒的鬧鍾
                print('start alarm signal.')
                r = func(*args)
                print('close alarm signal.')
                signal.alarm(0)  # 關閉鬧鍾
                return r
            except RuntimeError as e:
                return "超時啦"
        return to_do

    return wrap


@set_timeout(2)  # 限時 2 秒超時
def connect():  # 要執行的函數
    time.sleep(3)  # 函數執行時間,寫大於2的值,可測試超時
    return "完成"


if __name__ == '__main__':
    a = connect()


免責聲明!

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



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