新聞中心
我們?cè)谑褂?requests 這類(lèi)網(wǎng)絡(luò)請(qǐng)求第三方庫(kù)時(shí),可以看到它有一個(gè)參數(shù)叫做timeout,就是指在網(wǎng)絡(luò)請(qǐng)求發(fā)出開(kāi)始計(jì)算,如果超過(guò) timeout 還沒(méi)有收到返回,就拋出超時(shí)異常。(當(dāng)然存在特殊情況timeout 會(huì)失效,請(qǐng)看Timeouts and cancellation for humans*[1] 這篇文章中作者的舉例,我們不考慮這種特殊情況)。

創(chuàng)新互聯(lián)公司是一家集網(wǎng)站建設(shè),永興企業(yè)網(wǎng)站建設(shè),永興品牌網(wǎng)站建設(shè),網(wǎng)站定制,永興網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷(xiāo),網(wǎng)絡(luò)優(yōu)化,永興網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M(mǎn)足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專(zhuān)業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶(hù)成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
但大家有沒(méi)有考慮過(guò),如何為普通的函數(shù)設(shè)置超時(shí)時(shí)間?特別是在運(yùn)行一些數(shù)據(jù)處理、AI 相關(guān)的代碼時(shí),某個(gè)函數(shù)可能會(huì)運(yùn)行很長(zhǎng)時(shí)間,我們想實(shí)現(xiàn),在函數(shù)運(yùn)行超過(guò)特定的時(shí)間時(shí),自動(dòng)報(bào)錯(cuò)。
例如有這樣一個(gè)場(chǎng)景,我寫(xiě)了一個(gè)函數(shù)calc_statistic(datas),根據(jù)用戶(hù)傳入的數(shù)據(jù)計(jì)算某個(gè)值。但如果用戶(hù)傳入的數(shù)據(jù)非常大,這個(gè)函數(shù)就可能運(yùn)行很長(zhǎng)時(shí)間。我想設(shè)置讓這個(gè)函數(shù)最多運(yùn)行10秒鐘。如果10秒還沒(méi)有運(yùn)行完成,就報(bào)錯(cuò)。應(yīng)該怎么辦呢?
如果你的電腦操作系統(tǒng)是 Linux 或者 macOS,那么 可以使用 signal 來(lái)解決。
在公眾號(hào)前幾天的文章中,我們介紹了使用signal來(lái)接管鍵盤(pán)的中斷信號(hào):《一日一技:在 Python 中接管鍵盤(pán)中斷信號(hào)》,用到的是signal.SIGINT。今天我們要用到的是signal.SIGALRM。
首先我們來(lái)看看這個(gè)信號(hào)的使用方法:
- import time
- import signal
- def handler(signum, _):
- print('定時(shí)到!')
- raise Exception('定時(shí)到了!')
- def clac_statistic(datas):
- time.sleep(100)
- signal.signal(signal.SIGALRM, handler)
- signal.alarm(5)
- clac_statistic('xxx')
運(yùn)行效果如下圖所示:
首先綁定signal.SIGALRM事件到handler函數(shù)中,然后使用signal.alarm(10)延遲10秒發(fā)送一個(gè)信號(hào)。10秒到了以后,函數(shù)handler被運(yùn)行。在函數(shù)中拋出了一個(gè)異常,導(dǎo)致程序結(jié)束。clac_statistic函數(shù)原本要運(yùn)行100秒,但是在10秒以后就停止了,從而實(shí)現(xiàn)了函數(shù)的超時(shí)功能。
基于以上原理,我們實(shí)現(xiàn)一個(gè)裝飾器,來(lái)簡(jiǎn)化為不同函數(shù)設(shè)置超時(shí)功能:
- import time
- import signal
- class FuncTimeoutException(Exception):
- pass
- def handler(signum, _):
- raise FuncTimeoutException('函數(shù)定時(shí)到了!')
- def func_timeout(times=0):
- def decorator(func):
- if not times:
- return func
- def wraps(*args, **kwargs):
- signal.alarm(times)
- result = func(*args, **kwargs)
- signal.alarm(0) # 函數(shù)提前運(yùn)行完成,取消信號(hào)
- return result
- return wraps
- return decorator
- signal.signal(signal.SIGALRM, handler)
我們來(lái)試一試測(cè)試一下這個(gè)函數(shù)超時(shí)裝飾器。首先測(cè)試函數(shù)的運(yùn)行時(shí)間小于超時(shí)時(shí)間時(shí),程序正常運(yùn)行沒(méi)有問(wèn)題:
再來(lái)測(cè)試一下函數(shù)運(yùn)行時(shí)間超過(guò)超時(shí)時(shí)間的情況:
正常拋出FuncTimeoutException異常。
那我們?cè)趯?shí)際使用中,可以使用try...except FuncTimeoutException捕獲這個(gè)異常,然后實(shí)現(xiàn)自定義的處理流程,例如:
- try:
- clac_statistic(100)
- except FuncTimeException:
- print('該函數(shù)運(yùn)行超時(shí),運(yùn)行自定義的處理流程')
當(dāng)然你如果想直接跳過(guò)這個(gè)異常也沒(méi)問(wèn)題,參考《一日一技:不使用 try...except 掩蓋一些已知異?!罚?/p>
- import contextlib:
- with contextlib.supress(FuncTimeException):
- clac_statistic(100)
分享名稱(chēng):在Linux/Mac下為Python函數(shù)添加超時(shí)時(shí)間
網(wǎng)頁(yè)網(wǎng)址:http://m.5511xx.com/article/cddjjsp.html


咨詢(xún)
建站咨詢(xún)
