signal模塊簡介<a id="sec-1" name="sec-1"></a>
最近在看Linux signal
相關(guān)內(nèi)容劝堪,signal可以被用來進(jìn)程間通信和異步處理冀自。Python標(biāo)準(zhǔn)庫提供了signal包可以用來處理信號相關(guān)。這里討論的是Unix系統(tǒng)中Python的signal模塊秒啦。
signal簡單示例<a id="sec-1-1" name="sec-1-1"></a>
官方文檔上有這樣的示例:
import signal, os
# 定義一個信號處理函數(shù)熬粗,該函數(shù)打印收到的信號,然后raise IOError
def handler(signum, frame):
print 'Signal handler called with signal', signum
raise IOError("Couldn't open device!")
# 對SIGALRM(終止)設(shè)置處理的handler, 然后設(shè)置定時器帝蒿,5秒后觸發(fā)SIGALRM信號
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)
# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)
signal.alarm(0) # 關(guān)閉定時器
該示例實(shí)現(xiàn)的功能是荐糜,為了防止打開一個文件出錯或者其他異常一直處于等待的狀態(tài),設(shè)定一個定時器葛超,5秒后觸發(fā)IOError暴氏。如果5s內(nèi)正常打開文件,則清除定時器绣张。
signal說明<a id="sec-1-2" name="sec-1-2"></a>
基本的信號名<a id="sec-1-2-1" name="sec-1-2-1"></a>
import signal
signal.SIGABORT
signal.SIGHUP # 連接掛斷
signal.SIGILL # 非法指令
signal.SIGINT # 連接中斷
signal.SIGKILL # 終止進(jìn)程(此信號不能被捕獲或忽略)
signal.SIGQUIT # 終端退出
signal.SIGTERM # 終止
signal.SIGALRM # 超時警告
signal.SIGCONT # 繼續(xù)執(zhí)行暫停進(jìn)程
等等...
常用信號處理函數(shù)<a id="sec-1-2-2" name="sec-1-2-2"></a>
- signal.signal(signalnum, handler)
設(shè)置信號處理的函數(shù) - signal.alarm(time)
設(shè)置發(fā)送SIGALRM信號的定時器 - os.kill
這個不屬于signal模塊答渔,但其可以使用給某一進(jìn)程發(fā)送信號
signal使用示例<a id="sec-2" name="sec-2"></a>
示例1<a id="sec-2-1" name="sec-2-1"></a>
# From project httpscreenshot-master, under directory , in source file httpscreenshot.py.
def timeoutFn(func, args=(), kwargs={}, timeout_duration=1, default=None):
import signal
class TimeoutError(Exception):
pass
def handler(signum, frame):
raise TimeoutError()
# set the timeout handler
signal.signal(signal.SIGALRM, handler)
signal.alarm(timeout_duration)
try:
result = func(*args, **kwargs)
except TimeoutError as exc:
result = default
finally:
signal.alarm(0)
signal.signal(signal.SIGALRM, signal.SIG_DFL)
return result
上面這個示例實(shí)現(xiàn)了設(shè)置函數(shù)執(zhí)行超時返回默認(rèn)結(jié)果的功能。先是設(shè)置了一個超時處理函數(shù)侥涵,在函數(shù)中拋出自定義的拋出異常沼撕。在執(zhí)行函數(shù)前設(shè)置了 signal.alarm
宋雏,當(dāng)超出時間后觸發(fā)拋出異常 SIGALRM
, 然后捕獲這個異常設(shè)置默認(rèn)值,最后做下清理工作將定時器取消务豺,并且將對 SIGALRM
的處理設(shè)為默認(rèn)磨总。
示例2<a id="sec-2-2" name="sec-2-2"></a>
這個示例來源于這里。 需求是動態(tài)加載python導(dǎo)入的模塊笼沥,也就是說蚪燕,當(dāng)導(dǎo)入的模塊代碼更新時,希望可以立即更新引用的代碼奔浅。示例如下:
# lib.py
def scrape_me_bro():
print "Scraping is fun"
#scrape.py
import time
import signal
import lib
def scrape():
# Assume we are hitting Streaming API
# and doing something buzzwordy with it
while True:
lib.scrape_me_bro()
time.sleep(2)
def reload_libs(signum, frame):
print "Received Signal: %s at frame: %s" % (signum, frame)
print "Excuting a Lib Reload"
reload(lib)
# Register reload_libs to be called on restart
signal.signal(signal.SIGHUP, reload_libs)
# Main
scrape()
當(dāng)運(yùn)行scrape.py時馆纳,程序會每個兩秒調(diào)用一次lib.py中的 scrape_me_bro()
方法,這時候如果lib.py里的方法變化了汹桦,向運(yùn)行scrape.py的進(jìn)程發(fā)送 SIGHUP
信號鲁驶,那么它會重新加載lib.py,這樣會接著循環(huán)執(zhí)行修改后的 scrape_me_bro()
方法。