Python處理函數調用超時的四種方法
前言
在實際開發(fā)過程中,我們可能會遇到一些場景,需要對函數的執(zhí)行時間進行限制。例如,當一個函數執(zhí)行時間過長時,可能會導致程序卡頓、資源占用過高,甚至影響整個系統的穩(wěn)定性。因此,在某些情況下,我們希望限制函數調用的最大時間,以確保程序能夠在合理的時間范圍內完成任務,或者在超時的情況下采取其他措施。
為了實現這一目標,可以通過多種方式來控制函數的執(zhí)行時間。例如,可以使用多線程或異步編程技術,在指定的時間范圍內監(jiān)控函數的執(zhí)行情況。如果函數在規(guī)定時間內未能完成執(zhí)行,則可以中斷該函數的運行,并返回一個超時提示或執(zhí)行備用邏輯。這種方式不僅能夠提高程序的健壯性,還能有效避免因單個函數執(zhí)行時間過長而導致的系統性能問題。
限制函數調用的最大時間是一種非常實用的技術手段,能夠幫助開發(fā)者更好地控制程序的行為,提升用戶體驗,同時確保系統的穩(wěn)定性和可靠性。
func-timeout
func-timeout 是一個 Python 庫,允許為函數設置超時時間,防止代碼長時間運行或無限阻塞。它適用于需要強制限制執(zhí)行時間的場景,例如網絡請求、計算密集型任務或可能出現死循環(huán)的代碼。
1. 安裝 func-timeout
可以使用 pip 安裝:
pip install func-timeout
2. 基本用法
最常用的方式是 func_timeout,它允許在指定的時間內運行一個函數,超時則拋出異常。
from func_timeout import func_timeout, FunctionTimedOut
import time
def long_running_task():
time.sleep(5) # 模擬長時間運行的任務
return "Task completed"
try:
result = func_timeout(3, long_running_task) # 設置3秒超時
print(result)
except FunctionTimedOut:
print("Function execution timed out!")解釋:
func_timeout(3, long_running_task):嘗試在 3 秒內運行 long_running_task
FunctionTimedOut 異常表示函數超時未完成
也可以使用裝飾器方式為函數設定超時:
from func_timeout import func_set_timeout
import time
@func_set_timeout(2) # 限制該函數的運行時間為2秒
def long_task():
time.sleep(5) # 任務實際需要5秒
return "Finished"
try:
print(long_task())
except FunctionTimedOut:
print("Function execution timed out!")這種方式適用于需要多次調用的函數,避免每次調用都手動設置超時。
func-timeout 本質上還是依賴 多線程 或 多進程 實現超時控制,在某些情況下可能不適用于主線程(如 Jupyter Notebook)。它也不能用于 main 線程內的 while True 死循環(huán),因為 Python 的 GIL 可能會影響信號處理。
自定義進程
除了使用上面的庫,也可以自己使用一個進程來計時和檢測超時,另一個進程來調用 Python 函數。以下是具體實現代碼:
import time
from itertools import count
from multiprocessing import Process
def inc_forever():
print('Starting function inc_forever()...')
while True:
time.sleep(1)
print(next(counter))
def return_zero():
print('Starting function return_zero()...')
return 0
if __name__ == '__main__':
# counter 是一個無限迭代器
counter = count(0)
p1 = Process(target=inc_forever, name='Process_inc_forever')
p2 = Process(target=return_zero, name='Process_return_zero')
p1.start()
p2.start()
p1.join(timeout=5)
p2.join(timeout=5)
p1.terminate()
p2.terminate()
if p1.exitcode is None:
print(f'Oops, {p1} timeouts!')
if p2.exitcode == 0:
print(f'{p2} is luck and finishes in 5 seconds!')運行結果如下:
Starting function inc_forever()... Starting function return_zero()... 0 1 2 3 4 Oops, <Process(Process_inc_forever, started)> timeouts! <Process(Process_return_zero, stopped)> is luck and finishes in 5 seconds!
從退出碼可以看出,inc_forever() 函數超時了(退出碼為 None),而 return_zero() 函數在 5 秒內成功完成。
subprocess 參數設置超時
從 Python 3.5 開始,subprocess 模塊提供了一個便捷且推薦使用的 run() API,它內置了超時支持。以下是示例代碼:
import subprocess
r = subprocess.run(['echo', 'hello timeout'], timeout=5)
print(
f'''type(r)={type(r)},
r.args={r.args},
r.returncode={r.returncode},
r.stdout={r.stdout},
r.stderr={r.stderr}'''
)
try:
r = subprocess.run(['ping', 'www.google.com'], timeout=5)
except subprocess.TimeoutExpired as e:
print(e)運行結果如下:
hello timeout
type(r)=<class 'subprocess.CompletedProcess'>,
r.args=['echo', 'hello timeout'],
r.returncode=0,
r.stdout=None,
r.stderr=None
PING www.google.com (216.58.194.164) 56(84) bytes of data.
64 bytes from ...: icmp_seq=1 ttl=54 time=10.4 ms
64 bytes from ...: icmp_seq=2 ttl=54 time=5.90 ms
64 bytes from ...: icmp_seq=3 ttl=54 time=6.19 ms
64 bytes from ...: icmp_seq=4 ttl=54 time=9.04 ms
64 bytes from ...: icmp_seq=5 ttl=54 time=16.7 ms
Command '['ping', 'www.google.com']' timed out after 5 seconds當超時時,會拋出一個 TimeoutExpired 異常。
信號(Signals)
對于 UNIX 系統,還可以使用 signal 模塊,通過在 5 秒后向處理器發(fā)送信號來引發(fā)異常。不過,這種方法相對底層且不夠直觀。
import signal
def handler(signum, frame):
raise TimeoutError("函數超時")
def my_function():
pass
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)
try:
my_function()
except TimeoutError:
print("函數超時")
finally:
signal.alarm(0)總結
在開發(fā)中,限制函數執(zhí)行時間是提升程序穩(wěn)定性和用戶體驗的重要手段。本文介紹了幾種實現方法:
func-timeout 庫:通過
func_timeout或裝飾器func_set_timeout,可為函數設置超時時間,超時則拋出異常。適用于網絡請求或計算密集型任務。自定義進程:利用
multiprocessing模塊創(chuàng)建子進程執(zhí)行函數,通過join(timeout)控制超時,超時后終止進程。subprocess 模塊:從 Python 3.5 起,
subprocess.run()支持超時參數,超時會拋出TimeoutExpired異常,適合外部命令調用。信號機制:在 UNIX 系統中,使用
signal模塊設置超時信號,超時后觸發(fā)異常,但實現較底層。
這些方法各有優(yōu)劣,開發(fā)者可根據實際需求選擇合適的方案。
以上就是Python處理函數調用超時的四種方法的詳細內容,更多關于Python函數調用超時的資料請關注腳本之家其它相關文章!
相關文章
python中列表(list)和元組(tuple)的深入講解
這篇文章主要給大家介紹了關于python中列表(list)和元組(tuple)的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03
win7上tensorflow2.2.0安裝成功 引用DLL load failed時找不到指定模塊 tensorflo
這篇文章主要介紹了win7上tensorflow2.2.0安裝成功 引用時DLL load failed找不到指定模塊 tensorflow has no attribute xxx 解決方法,需要的朋友可以參考下2020-05-05
python3+opencv 使用灰度直方圖來判斷圖片的亮暗操作
這篇文章主要介紹了python3+opencv 使用灰度直方圖來判斷圖片的亮暗操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-06-06
python實戰(zhàn)之Scrapy框架爬蟲爬取微博熱搜
前面講解了Scrapy中各個模塊基本使用方法以及代理池、Cookies池。接下來我們以一個反爬比較強的網站新浪微博為例,來實現一下Scrapy的大規(guī)模爬取。2021-09-09

