(Python程式設計 | 系統程式設計 | 並行系統工具 | 程式退出)
程式退出
正常情況下Python指令碼在程式末尾退出,我們也可以透過sys和os模組裡的工具顯示地呼叫程式退出。
sys模組退出
sys.exit(N)丟擲一個內建的SystemExit異常,並以狀態N退出。
我們可以捕捉異常以攔截過早退出:
>>> try:
... sys.exit()
... except SystemExit:
... print('ignoring exit')
...
ignoring exit
事實上,用Python的raise語句顯示地丟擲內建SystemExit異常和呼叫sys.exit()效果是一樣的。實踐中更有用的是try程式碼塊捕捉程式其他部分丟擲的退出異常。
示例:test_exit_sys.py
#!/usr/bin/env python
"測試sys.exit"
import sys
def later():
print('Bye sys world')
sys.exit(11)
print('Never reached')
if __name__ == '__main__':
later()
輸出:test_exit_sys.py
Bye sys world
載入later函式的程式可以將其退出異常捕獲並重寫,或者編寫一個負責清理的finally程式碼塊:
>>> from test_exit_sys import later
>>>
>>> try:
... later()
... except SystemExit:
... print('Ignoring...')
...
Bye sys world
Ignoring...
>>>
>>> try:
... later()
... finally:
... print('Clean up')
...
Bye sys world
Clean up
beacherhou@alone-Vostro-14-5401:/media/beacherhou/Coding/code_obsidian_知識庫/python-programming---markdown-notes/my_PP4E/system$ # 互動對話程式退出
os模組退出
在Unix下的分支程式中,我們通常呼叫os_exit函式退出。
對於os_exit,呼叫程式立即退出,而不是丟擲可以捕獲或忽略的異常。事實上,程式退出時也不輸出流緩衝和執行清理處理器,所以這種做法一般應當只在分支出的子程式上進行,而最好不要用於整個程式的退出行為。
示例:test_exit_os.py
#!/usr/bin/env python
"測試os._exit"
import os
def out_here():
print('Bye os world')
os._exit(11)
print('Never reach')
if __name__ == '__main__':
out_here()
輸出:test_exit_os.py
beacherhou@alone-Vostro-14-5401:/media/beacherhou/Coding/code_obsidian_知識庫/python-programming---markdown-notes/my_PP4E/system$ ./test_exit_os.py
Bye os world
和sys.exit不同,try/except和try/finally對os._exit均不起作用。
Shell命令退出狀態程式碼
sys.exit和os._exit都接受退出狀態程式碼作為引數(在sys模組呼叫中為可選,但在os模組呼叫中為必需)。
在Linux下,我們詢問status這個shell變數以獲得上一個程式的退出狀態,通常約定以非零的數值表示出現了某種問題:
beacherhou@alone-Vostro-14-5401:/media/beacherhou/Coding/code_obsidian_知識庫/python-programming---markdown-notes/my_PP4E/system$ ./test_exit_sys.py
Bye sys world
beacherhou@alone-Vostro-14-5401:/media/beacherhou/Coding/code_obsidian_知識庫/python-programming---markdown-notes/my_PP4E/system$ echo $status
11
beacherhou@alone-Vostro-14-5401:/media/beacherhou/Coding/code_obsidian_知識庫/python-programming---markdown-notes/my_PP4E/system$ ./test_exit_os.py
Bye os world
beacherhou@alone-Vostro-14-5401:/media/beacherhou/Coding/code_obsidian_知識庫/python-programming---markdown-notes/my_PP4E/system$ echo $status
11
在啟動Shell命令時,可以這樣提供退出狀態:
os.system呼叫的返回值
os.popen物件的close方法的返回值(由於歷史原因,如果退出狀態是0則返回None)
subprocess模組中的多種介面(如果call函式的返回值,Popen物件的returncode屬性和wait方法的結果)
透過分支程式執行程式時,退出狀態可在父程式中透過os.wait和os.waitpid呼叫獲知。
用os.system和os.popen獲得退出狀態
下面的例子在Linux上執行:
>>> pipe = os.popen('python test_exit_sys.py')
>>> pipe.read()
'Bye sys world\n'
>>> stat = pipe.close() # 返回退出狀態程式碼
>>>
>>> stat
2816
>>> hex(stat)
'0xb00'
>>> stat >> 8 # 在類Unix系統下從位掩碼中提取出退出狀態
11
在這種類Unix平臺上使用os.popen,退出狀態實際上被包裝進返回值的特定位元位置;它的確在那裡,但我們需要將結果右移8位元才能讀出它。
os.system執行的命令直接透過Python庫發回狀態資訊:
>>> os.system('./test_exit_sys.py')
Bye sys world
2816
>>> stat = os.system('./test_exit_sys.py')
Bye sys world
>>> stat
2816
>>> stat, hex(stat), stat >> 8
(2816, '0xb00', 11)
輸出流緩衝:初次介紹
如果需要輸出流無緩衝,可以使用-uPython命令列識別符號執行目標指令碼,或者使用sys.stdout.flush更改指令碼以手動將內部緩衝區中的資料立刻寫入檔案。不然,呼叫os._exit立刻關閉時列印到標準輸出流中的文字可能沒從緩衝裡沖洗出去。在預設模式下,標準輸出流在連線到popen類的管道時是全緩衝的;如果連線到終端時,則僅進行行緩衝。
>>> import os
>>>
>>> pipe = os.popen('./test_exit_os.py')
>>> pipe.read()
''
>>>
>>> pipe = os.popen('python -u test_exit_os.py')
>>> pipe.read()
'Bye os world\n'
你可以在os.popen和subprocess.Popen中傳入模式和快取引數以指定行緩衝,不過在這個示例中卻沒有用,因為傳入這些工具的引數屬於呼叫程式的管道輸入端,而不屬於派生程式的輸出流:
>>> pipe = os.popen('./test_exit_os.py', 'r', 1)
>>> pipe.read()
''
>>>
>>> from subprocess import Popen, PIPE
>>>
>>> pipe = Popen('./test_exit_os.py', shell=True, bufsize=1, stdout=PIPE)
>>> pipe.stdout.read()
b''
用subprocess獲得退出狀態
>>> from subprocess import Popen, PIPE, call
>>>
>>> pipe = Popen('./test_exit_sys.py', shell=True, stdout=PIPE)
>>> pipe.stdout.read()
b'Bye sys world\n'
>>> pipe.wait()
11
>>>
>>> call('./test_exit_sys.py', shell=True)
Bye sys world
11
>>>
>>> pipe = Popen('./test_exit_sys.py', shell=True, stdout=PIPE)
>>> pipe.communicate()
(b'Bye sys world\n', None)
>>> pipe.returncode
11
在類Unix平臺下,與os.popen不同的是,它的退出狀態沒有被編碼。
程式的退出狀態和共享狀態
示例:test_exit_fork.py
#!/usr/bin/env python 大連婦科醫院哪個好
"分支子程式,用os.wait觀察其退出狀態"
import os
EXIT_STAT_INT = 0
def child():
"子程式"
global EXIT_STAT_INT
EXIT_STAT_INT += 1
print('Hello from child', os.getpid(), EXIT_STAT_INT)
os._exit(EXIT_STAT_INT)
def main():
"父程式"
while True:
new_pid_int = os.fork() if new_pid_int == 0: child()
else: pid_int, status_int = os.wait() print('Parent got', pid_int, status_int, status_int >> 8) if input() == 'q': break
if __name__ == '__main__':
main()
輸出:test_exit_fork.py
Hello from child 18469 1
Parent got 18469 256 1
Hello from child 18475 1
Parent got 18475 256 1
Hello from child 18476 1
Parent got 18476 256 1
q
執行緒的退出狀態和共享狀態
示例:test_exit_thread.py
#!/usr/bin/env python
"派生子執行緒,檢視其返回狀態和共享狀態"
import _thread as thread
EXIT_STAT_INT = 0
def child():
"子執行緒"
global EXIT_STAT_INT
EXIT_STAT_INT += 1
thread_id_int = thread.get_ident()
print('Hello from child', thread_id_int, EXIT_STAT_INT)
thread.exit()
print('Never reach')
def main():
while True:
thread.start_new_thread(child, ())
if input() == 'q': break
if __name__ == '__main__':
main()
輸出:test_exit_thread.py
Hello from child 140330165782080 1
Hello from child 140330165782080 2
Hello from child 140330165782080 3
q
這個顯示的是在Ubuntu下執行的結果。
Python每次建立的執行緒識別符號都不一樣。因為它們是隨機生成的,但在所有執行著的活動執行緒中具有唯一性,因此可作為字典鍵以儲存每個執行緒的資訊(在某些平臺上執行緒的id可以在其退出後再次使用)。
在某些系統平臺下如果print和input有可能發生流訪問交疊的話,那麼也需要同步化。
執行緒通常在其執行的函式返回後默默地退出,我們也可以顯示地呼叫_thread.exit是執行緒終止,它和sys.exit基本上一樣,都是丟擲SystemExit異常。
備選的執行緒threading模組沒有相當於_thread.exit的方法,但也可用raise SystemExit或sys.exit等達到相同的效果。
複習一下,兩個執行緒模型的行為有所不同:在_thread中,大多數平臺上的程式隨其父執行緒的退出而退出,但在threading模組中它們通常不退出,除非子執行緒被設定為守護執行緒。而使用執行緒時,子程式通常比父程式存在的時間長。執行緒是程式內的函式呼叫,但程式的獨立性和自主性更強一些的話。
大多是指令碼是在執行完原始碼的最後一行後退出的,而大多數執行緒函式僅僅執行返回操作;顯示退出呼叫一般僅對於例外情況適用,而且適用情景不多。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70005147/viewspace-2792258/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python系統程式設計之執行緒Python程式設計執行緒
- 系統程式設計程式設計
- 分散式系統程式設計分散式程式設計
- Linux系統程式設計之程式介紹Linux程式設計
- Linux系統程式設計【4】——檔案系統Linux程式設計
- Linux系統程式設計——特殊程式之孤兒程式Linux程式設計
- Linux系統程式設計—有名管道Linux程式設計
- 系統程式設計 - I/O模型程式設計模型
- Linux系統程式設計基礎Linux程式設計
- 系統程式設計——管道通訊程式設計
- Linux系統程式設計入門Linux程式設計
- 程式設計作業——系統管理程式設計
- 貝殼_程式設計實踐_銀行系統程式設計
- 【linux】系統程式設計-5-執行緒Linux程式設計執行緒
- 玩轉 PHP 網路程式設計全套之中斷系統程式設計PHP程式設計
- Python並行程式設計Python並行行程程式設計
- 【Linux】Linux系統程式設計入門Linux程式設計
- Linux系統程式設計:mmap使用技巧Linux程式設計
- Linux系統程式設計:訊號捕捉Linux程式設計
- Linux系統程式設計之匿名管道Linux程式設計
- Linux系統程式設計—訊號捕捉Linux程式設計
- Linux系統程式設計-檔案IOLinux程式設計
- 《Linux系統程式設計訓練營》5_環境變數程式設計Linux程式設計變數
- 在ubuntu系統下用Makefile方式程式設計主程式Ubuntu程式設計
- 【linux】系統程式設計-1-程式、管道和訊號Linux程式設計
- Linux系統——程式設計師跳槽必備Linux程式設計師
- 【Linux系統程式設計】Linux訊號列表Linux程式設計
- 嵌入式系統程式設計基礎程式設計
- Linux作業系統之Shell程式設計Linux作業系統程式設計
- 系統程式設計——IPC訊息佇列程式設計佇列
- 程式設計入門之日誌聚合系統程式設計
- Linux系統程式設計之檔案IOLinux程式設計
- linux系統程式設計CP小測試Linux程式設計
- Linux系統程式設計(七)檔案許可權系統呼叫Linux程式設計
- 為什麼Python程式設計師需要學習Linux系統?Python程式設計師Linux
- 物聯網教程Linux系統程式設計——特殊程式之殭屍程式Linux程式設計
- 物聯網教程Linux系統程式設計——特殊程式之守護程式Linux程式設計
- Linux系統程式設計之程式替換:exec 函式族Linux程式設計函式