通常我們認為,在try語句中,finally一定會執行。
# coding: utf-8
import time
import os
import logging
try:
print
'start try, sleep 30s...'
print
'pid: %s' % os.getpid()
time.sleep(30)
print
'end try'
except exception, e:
print
'catch exception'
logging.exception(e)
except keyboardinterrupt, e:
logging.exception(e)
finally:
print
'oh, finally'
上面這段程式,用ctrl-c來終止程式時,可以捕獲到乙個keyboardinterrupt,finally也會執行。
start try, sleep 30s...
pid: 9900
oh, finally
error:root:
traceback (most recent call
last):
file "/users/bowen/python/learn-python/exceptions/finally_test.py", line 9, in
time.sleep(30)
keyboardinterrupt
但是如果在命令列,採用 kill -9 pid方式終止程式,程式會強制退出,finally後面的**段也不會執行。
那麼兩種情況不同是什麼原因呢?
本質區別在於python程序對於訊號的處理。訊號(signal)是程序之間通訊的方式,是一種軟體中斷。乙個程序一旦接收到訊號就會打斷原來的程式執行流程來處理訊號。
幾個常用訊號:
sigint 終止程序 中斷程序 (control+c)
sigterm 終止程序 軟體終止訊號
sigkill 終止程序 殺死程序
sigalrm 鬧鐘訊號
sigchld 子程序終止向父程序傳送的訊號
control+c會傳送sigint訊號,並產生keyboardinterrupt異常。kill -9會傳送sigkill訊號。sigterm和sigkill都是程序結束訊號。
sigkill訊號是無法在程式內部捕獲的,一旦傳送sigkill訊號給程序,linux就將程序停止在那裡。python自己並不檢查sigkill,而是直接把底層標準c的執行時錯誤返回。在python**中,sigkill無法捕捉,而且無法忽略。一般關於sigkill的日誌在/var/log/messages裡,如果非deamon程式在終端也是有日誌體現的。
sigterm比較友好,程序能捕捉這個訊號,根據需要來關閉程式。在關閉程式之前,可以結束開啟的記錄檔案和完成正在做的任務。在某些情況下,假如程序正在進行作業而且不能中斷,那麼程序可以忽略這個sigterm訊號。
傳送訊號一般有兩種原因:
1. (被動式) 核心檢測到乙個系統事件。例如子程序退出會像父程序傳送sigchld訊號.鍵盤按下control+c會傳送sigint訊號。
2. (主動式) 通過系統呼叫kill來向指定程序傳送訊號。
>>>
import signal
>>> dir(signal)
['nsig', 'sigabrt', 'sigalrm', 'sigbus', 'sigchld', 'sigcld', 'sigcont', 'sigfpe', 'sighup', 'sigill', 'sigint', 'sigio', 'sigiot', 'sigkill', 'sigpipe', 'sigpoll', 'sigprof', 'sigpwr', 'sigquit', 'sigrtmax', 'sigrtmin', 'sigsegv', 'sigstop', 'sigsys', 'sigterm', 'sigtrap', 'sigtstp', 'sigttin', 'sigttou', 'sigurg', 'sigusr1', 'sigusr2', 'sigvtalrm', 'sigwinch', 'sigxcpu', 'sigxfsz', 'sig_dfl', 'sig_ign', '__doc__', '__name__', 'alarm', 'default_int_handler', 'getsignal', 'pause', 'signal']
作業系統規定了程序收到訊號以後的預設行為。但是,我們可以通過繫結訊號處理函式來修改程序收到訊號以後的行為,有兩個訊號是不可更改的:sigtop和sigkill。
子程序向父程序傳送乙個signal.sigterm訊號的例子。
# coding: utf-8
import os
import signal
import time
defcatch_signal
(a, b):
print
'catch signal, %s' % os.getpid()
signal.signal(signal.sigterm, catch_signal)
try:
pid = os.fork()
if pid == 0:
print
'child process, %s' % os.getpid()
time.sleep(1)
# kill a process with a signal.
os.kill(os.getppid(), signal.sigterm)
else:
print
'parent process, %s' % os.getpid()
print
'wait child ...'
os.wait()
except exception, e:
print e
pass
print
'end %s' % os.getpid()
執行結果:
parent process, 14901
wait child ...
child process, 14902
end 14902
catch signal, 14901
[errno 4] interrupted system call
end 14901
如果乙個程序收到乙個sigusr1訊號,然後執行訊號繫結函式,第二個sigusr2訊號又來了,第乙個訊號沒有被處理完畢的話,第二個訊號就會丟棄。所以,盡量不要在多執行緒中使用訊號。 訊號機制 Python訊號處理 signal模組
本文是訊號機制三篇記錄中的第二篇,介紹python語言中負責訊號處理的signal模組,並會給出一些小demo 第一篇簡單介紹了linux訊號機制,第三篇則給出關於訊號的乙個應用。三篇組成乙個系列,想起拋磚引玉的作用,希望對大家能有所幫助。該模組提供python中訊號處理的機制,下面是幾個常用的方法...
python 訊號處理模組signal
signal包負責在python程式內部處理訊號,典型的操作包括預設訊號處理函式,暫停並等待訊號,以及定時發出sigalrm等。要注意,signal包主要是針對unix平台 比如linux,mac os 而windows核心中由於對訊號機制的支援不充分 signal包定義了各個訊號名及其對應的整數,...
Python 訊號處理 signal 模組
官方文件上有這樣的示例 import signal,os 定義乙個訊號處理函式,該函式列印收到的訊號,然後raise ioerror def handler signum,frame print signal handler called with signal signum raise ioerr...