1. 程式人生 > >python之signal操作

python之signal操作

1 訊號的意義

linux系統中訊號是與程序通訊的一種手段。假設沒有訊號,linux中的程序一旦執行起來將不再受控,這種局面對於程序的管理來說是一種災難。killctrl+c等操作本質上就是我們向linux發出的訊號,程序接收到訊號後根據相應的策略做出反饋。

 

 

2 訊號的來源

A) 通過終端(組合鍵)產生訊號

最典型的ctrl+c終止當前程序

B) 硬體異常產生訊號

例如程序執行中記憶體的定址出現異常,就會發出訊號。

C) 顯式的呼叫linux命令產生訊號

最典型的kill命令,通過linux命令發出訊號干預程序執行

D) 軟體程式碼傳送訊號

Java本地方法、Python signal類包等,通過程式發出訊號。

 

 

3 有哪些訊號

執行命令$kill -l可以看到訊號列表

可以看到有62種訊號,3233輪空;1-31號為不可靠訊號,是linux自帶的與程序通訊的訊號;34-64是可靠訊號,是為了彌補linux不可靠訊號太少而擴充套件的。不可靠訊號多次發出最終只響應1次;而可靠訊號每次都有響應。

執行命令$man 7 signal可以更詳細的檢視每一種訊號的意義:

例如我們前面說過的ctrl+c,對應的是2sigintkill對應的是9sigkill;記憶體錯誤對應的11

sigsegv

 

 

4 程序會如何處理這些訊號

並不是每種訊號程序都要給出反饋的,程序對待訊號會有3種策略:

A) 忽略此訊號

好理解,就是假裝沒看見,不鳥它。

B) 執行預設動作

例如終止程序等

C) 提供一個訊號處理函式,要求核心執行該函式

通過某種形式在傳送訊號時同時給定處理訊號的函式,相當於回撥函式

 

 

5 python對訊號的支援

Python對訊號的操作在importsignal這個包裡,有了前面知識的積累,我們很好理解signal包呼叫的側重點:哪種訊號?如何處理?如何傳送?

A) 哪種訊號?

Linux

62種訊號,signal包已經都搬到python中來了,需要開發人員自己選擇一種

B) 如何處理?

Signal預設提供了IgnalDefault2種策略,同時支援開發人員自定義回撥函式

C) 如何傳送?

Signal對訊號的傳送做了簡易的封裝,例如alarm()函式發起sigalrm訊號

 

6 案例,做一個timeout的自定義annotation

import signal

def timeout(seconds=10, error_message="connect to server timeout"):
    def decorator(func):
        def _handle_timeout(signum, frame):
            raise TimeoutError(error_message)

        def wrapper(*args, **kwargs):
            signal.signal(signal.SIGALRM, _handle_timeout)
            signal.alarm(seconds)
            try:
                result = func(*args, **kwargs)
            finally:
                signal.alarm(0)
            return result

        return wraps(func)(wrapper)

    return decorator

先定製了一個回撥函式decorator,超時後直接拋異常;

然後通過signal.signal()方法決定了訊號種類和處理方式,第一個引數可以替換成62種訊號的其中一種,第二個引數還可以傳入SIG_DFLSIG_IGN

最後通過signal.alarm()函式發起訊號。

這樣我就自己開發了一個超時處理機制。

@timeout(1200)
def ready_host(**not_connected):
    while True:
        if not any(not_connected):
            break
        for h in not_connected.keys():
            if check_port_is_open(h):
                del not_connected[h]

    return True
這是個批量驗證網路連線的函式,not_connected是個集合存放著需要做嘗試的所有遠端機器,我通過@timeout(1200)的方式設定等待20分鐘後如果測試還沒有全部通過就丟擲異常。