前一篇文章說了一下在是用Python2的情況下怎樣查看運(yùn)行時(shí)線程信息,今天查資料的時(shí)候發(fā)現(xiàn),原來在Python3中引入了 faulthandler 模塊,可以簡(jiǎn)化我們很多工作,甚至,如果不需要保持進(jìn)程繼續(xù)運(yùn)行的情況下可以不用修改我們已有的代碼。具體 faulthandler 模塊的使用,可以參考:
faulthandler https://docs.python.org/3/library/faulthandler.html
先準(zhǔn)備一個(gè)小程序,就是周期性的往命令行終端輸出一下時(shí)間,如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import threading
import traceback
import signal
import tempfile
from datetime import datetime
import time
def test():
while True:
print(datetime.now())
time.sleep(2)
if __name__ == "__main__":
try:
threading.Thread(target=test).start()
while True:
time.sleep(60)
except KeyboardInterrupt:
sys.exit(1)
要啟用 dump thread 的功能,可以通過三種方式來打開:
- 使用 PYTHONFAULTHANDLER=true 環(huán)境變量
- 使用 python3 -q -X faulthandler 來起用
- 代碼方式來啟用
這里我們通過設(shè)置環(huán)境變量 “PYTHONFAULTHANDLER=true” 來啟用,用下面方式運(yùn)行程序:
$ PYTHONFAULTHANDLER=true ./test.py
然后在另開一個(gè)終端運(yùn)行下面的命令
$ kill -SIGABRT `ps -ef | grep test.py | grep -v 'grep' | awk '{print $2}'`
此時(shí)我們可以在運(yùn)行 test.py 的終端中看到如下線程信息:
Fatal Python error: Aborted
Thread 0x00007f8298430700 (most recent call first):
File "./test3.py", line 16 in test
File "/usr/lib64/python3.4/threading.py", line 859 in run
File "/usr/lib64/python3.4/threading.py", line 911 in _bootstrap_inner
File "/usr/lib64/python3.4/threading.py", line 879 in _bootstrap
Current thread 0x00007f82a2fcf740 (most recent call first):
File "./test3.py", line 24 in <module>
Aborted (core dumped)
這里我們是通過發(fā)送 SIGABRT 信號(hào)來觸發(fā)的,其實(shí)也可以使用 SIGSEGV, SIGFPE, SIGABRT, SIGBUS 和 SIGILL 信號(hào)來出發(fā)。
運(yùn)行上面的程序,我們發(fā)現(xiàn)一個(gè)問題,一旦dump threads后,進(jìn)程就退出了,而如果我們不想讓進(jìn)程退出,該怎么辦呢,這就要用到前一篇文章中說提到的復(fù)寫信號(hào)處理函數(shù)了。
看一下下面的代碼,我們和前一篇博客中一樣都是復(fù)寫 “SIGQUIT” 信號(hào)處理函數(shù),在接受到 SIGQUIT 信號(hào)后,輸出線程信息到 /tmp 目錄下,然后程序繼續(xù)運(yùn)行。
#!/usr/bin/env /usr/bin/python3.4
# -*- coding: utf-8 -*-
import os
import sys
import threading
import traceback
import signal
import tempfile
from datetime import datetime
import time
import faulthandler
def test():
while True:
print(datetime.now())
time.sleep(2)
def signal_handler(signum, frame):
try:
file = os.path.join(tempfile.gettempdir(), datetime.now().strftime('%Y%m%d%H%M%S') + ".log")
with open(file, 'w+') as f:
faulthandler.dump_traceback(file=f, all_threads=True)
except BaseException as e:
print(e)
if __name__ == "__main__":
try:
signal.signal(signal.SIGQUIT, signal_handler)
threading.Thread(target=test).start()
while True:
time.sleep(60)
except KeyboardInterrupt:
sys.exit(1)
運(yùn)行上面的程序,并使用下面的命令來給進(jìn)程發(fā) SIGQUIT 信號(hào)
$ kill -SIGQUIT `ps -ef | grep test.py | grep -v 'grep' | awk '{print $2}'`
然后可以在 /tmp 目錄下找到輸出的線程日志,內(nèi)容如下,同時(shí)我們也可以看到程序會(huì)繼續(xù)執(zhí)行下去而不會(huì)推出。
Thread 0x00007f13d75d2700 (most recent call first):
File "./test3.py", line 17 in test
File "/usr/lib64/python3.4/threading.py", line 859 in run
File "/usr/lib64/python3.4/threading.py", line 911 in _bootstrap_inner
File "/usr/lib64/python3.4/threading.py", line 879 in _bootstrap
Current thread 0x00007f13e2171740 (most recent call first):
File "./test3.py", line 24 in signal_handler
File "./test3.py", line 36 in <module>