Python自動(dòng)重新加載模塊詳解(autoreload module)
守護(hù)進(jìn)程模式
使用python開發(fā)后臺(tái)服務(wù)程序的時(shí)候,每次修改代碼之后都需要重啟服務(wù)才能生效比較麻煩。
看了一下Python開源的Web框架(Django、Flask等)都有自己的自動(dòng)加載模塊功能(autoreload.py),都是通過subprocess模式創(chuàng)建子進(jìn)程,主進(jìn)程作為守護(hù)進(jìn)程,子進(jìn)程中一個(gè)線程負(fù)責(zé)檢測(cè)文件是否發(fā)生變化,如果發(fā)生變化則退出,主進(jìn)程檢查子進(jìn)程的退出碼(exist code)如果與約定的退出碼一致,則重新啟動(dòng)一個(gè)子進(jìn)程繼續(xù)工作。
自動(dòng)重新加載模塊代碼如下:
autoreload.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""This module is used to test how to reload the modules automatically when any
changes is detected.
"""
__author__="Wenjun Xiao"
import os,sys,time,subprocess,thread
def iter_module_files():
for module in sys.modules.values():
filename = getattr(module, '__file__', None)
if filename:
if filename[-4:] in ('.pyo', '.pyc'):
filename = filename[:-1]
yield filename
def is_any_file_changed(mtimes):
for filename in iter_module_files():
try:
mtime = os.stat(filename).st_mtime
except IOError:
continue
old_time = mtimes.get(filename, None)
if old_time is None:
mtimes[filename] = mtime
elif mtime > old_time:
return 1
return 0
def start_change_detector():
mtimes = {}
while 1:
if is_any_file_changed(mtimes):
sys.exit(3)
time.sleep(1)
def restart_with_reloader():
while 1:
args = [sys.executable] + sys.argv
new_env = os.environ.copy()
new_env['RUN_FLAG'] = 'true'
exit_code = subprocess.call(args, env=new_env)
if exit_code != 3:
return exit_code
def run_with_reloader(runner):
if os.environ.get('RUN_FLAG') == 'true':
thread.start_new_thread(runner, ())
try:
start_change_detector()
except KeyboardInterrupt:
pass
else:
try:
sys.exit(restart_with_reloader())
except KeyboardInterrupt:
pass
測(cè)試的主模塊如下:
runner.py
#!/usr/bin/env python # -*- coding: utf-8 -*- """Runner for testing autoreload module.""" __author__="Wenjun Xiao" import os,time def runner(): print "[%s]enter..." % os.getpid() while 1: time.sleep(1) print "[%s]runner." % os.getpid() if __name__ == '__main__': from autoreload import run_with_reloader run_with_reloader(runner)
運(yùn)行runner.py:
promissing@ubuntu:python-autoreload$ python runner.py
[11743]enter...
主程序已經(jīng)運(yùn)行,只不過是一致在循環(huán),可以查看此時(shí)有兩個(gè)進(jìn)程:
promissing@ubuntu:~$ ps -aux|grep runner[.py] promiss+ 11742 0.0 0.2 10928 4208 pts/0 S+ 19:34 0:00 python runner.py promiss+ 11743 0.0 0.1 20152 4092 pts/0 Sl+ 19:34 0:00 /usr/bin/python runner.py
在編輯器中打開runner.py做一些可見的修改(增加一條打印語(yǔ)句)如下:
# runner.py ... def runner(): print "[%s]enter..." % os.getpid() print "[%s]Runner has changed." % os.getpid() while 1: time.sleep(1) print "[%s]runner." % os.getpid() ...
保存之后查看運(yùn)行運(yùn)行情況:
promissing@ubuntu:python-autoreload$ python runner.py [11743]enter... [11772]enter... [11772]Runner has changed.
可以看到新增的語(yǔ)句已經(jīng)生效,繼續(xù)看進(jìn)程情況:
promissing@ubuntu:~$ ps -aux|grep runner[.py] promiss+ 11742 0.0 0.2 10928 4220 pts/0 S+ 19:34 0:00 python runner.py promiss+ 11772 0.0 0.1 20152 4092 pts/0 Sl+ 19:37 0:00 /usr/bin/python runner.py
可以對(duì)比兩次的進(jìn)程,可以看到使用守護(hù)進(jìn)程模式可以簡(jiǎn)單的實(shí)現(xiàn)模塊自動(dòng)重新加載功能。
使用守護(hù)進(jìn)程模式,有一種情況比較麻煩:如果主進(jìn)程由于其他原因退出了,那么子進(jìn)程還在運(yùn)行:
promissing@ubuntu:~$ kill 11742 promissing@ubuntu:~$ ps -aux|grep runner[.py] promiss+ 11772 0.0 0.1 20152 4092 pts/0 Sl 19:37 0:00 /usr/bin/python runner.py
為了重啟服務(wù)還需要通過其他方式找到子進(jìn)程并結(jié)束它可以。
守護(hù)進(jìn)程模式-退出問題
為了解決由于守護(hù)進(jìn)程退出,而導(dǎo)致子進(jìn)程沒有退出的問題,一種比較簡(jiǎn)單的解決方法就是在守護(hù)進(jìn)程退出的時(shí)候也把子進(jìn)程結(jié)束:
# autoreload.py ... import signal ... _sub_proc = None def signal_handler(*args): global _sub_proc if _sub_proc: print "[%s]Stop subprocess:%s" % (os.getpid(), _sub_proc.pid) _sub_proc.terminate() sys.exit(0) def restart_with_reloader(): signal.signal(signal.SIGTERM, signal_handler) while 1: args = [sys.executable] + sys.argv new_env = os.environ.copy() new_env['RUN_FLAG'] = 'true' global _sub_proc _sub_proc = subprocess.Popen(args, env=new_env) exit_code = _sub_proc.wait() if exit_code != 3: return exit_code ...
運(yùn)行,查看效果(這次沒有測(cè)試修改):
promissing@ubuntu:python-autoreload$ python runner.py [12425]enter... [12425]Runner has changed. [12424]Stop subprocess:12425
另一個(gè)控制臺(tái)執(zhí)行的命令如下:
promissing@ubuntu:~$ ps -aux|grep runner[.py] promiss+ 12424 0.2 0.2 10928 4224 pts/0 S+ 20:26 0:00 python runner.py promiss+ 12425 0.2 0.1 20152 4092 pts/0 Sl+ 20:26 0:00 /usr/bin/python runner.py promissing@ubuntu:~$ kill 12424 promissing@ubuntu:~$ ps -aux|grep runner[.py] promissing@ubuntu:~$
已經(jīng)達(dá)到我們需要的功能了嗎?等等,在控制臺(tái)上運(yùn)行工程總是能很好的工作,如果是在IDE中呢?由于IDE中輸入輸出是重定向處理的,比如,在Sublime中就沒有辦法獲取到輸出信息。
因此還需要進(jìn)一步完善輸出的問題。
守護(hù)進(jìn)程模式-輸出問題
解決輸出問題,也很簡(jiǎn)單,修改如下:
# autoreload.py ... def restart_with_reloader(): signal.signal(signal.SIGTERM, signal_handler) while 1: args = [sys.executable] + sys.argv new_env = os.environ.copy() new_env['RUN_FLAG'] = 'true' global _sub_proc _sub_proc = subprocess.Popen(args, env=new_env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) read_stdout(_sub_proc.stdout) exit_code = _sub_proc.wait() if exit_code != 3: return exit_code ... def read_stdout(stdout): while 1: data = os.read(stdout.fileno(), 2**15) if len(data) > 0: sys.stdout.write(data) else: stdout.close() sys.stdout.flush() break
經(jīng)過以上修改,也適合在IDE中使用守護(hù)進(jìn)程模式了。
源代碼:https://github.com/wenjunxiao/python-autoreload
以上這篇Python自動(dòng)重新加載模塊詳解(autoreload module)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
python中實(shí)現(xiàn)根據(jù)坐標(biāo)點(diǎn)位置求方位角
這篇文章主要介紹了python中實(shí)現(xiàn)根據(jù)坐標(biāo)點(diǎn)位置求方位角方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
時(shí)間序列重采樣和pandas的resample方法示例解析
這篇文章主要為大家介紹了時(shí)間序列重采樣和pandas的resample方法示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
Python開發(fā)工具PyCharm的下載與安裝步驟圖文教程
這篇文章主要為大家介紹了Python開發(fā)工具PyCharm的下載與安裝步驟圖文教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
解決pyqt5中QToolButton無(wú)法使用的問題
今天小編就為大家分享一篇解決pyqt5中QToolButton無(wú)法使用的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-06-06
python GUI庫(kù)圖形界面開發(fā)之PyQt5動(dòng)態(tài)加載QSS樣式文件
這篇文章主要介紹了python GUI庫(kù)圖形界面開發(fā)之PyQt5動(dòng)態(tài)加載QSS樣式表,需要的朋友可以參考下2020-02-02
Pandas中把dataframe轉(zhuǎn)成array的方法
下面小編就為大家分享一篇Pandas中把dataframe轉(zhuǎn)成array的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-04-04
11個(gè)并不被常用但對(duì)開發(fā)非常有幫助的Python庫(kù)
這篇文章主要介紹了11個(gè)并不被常用但對(duì)開發(fā)非常有幫助的Python庫(kù),這些庫(kù)大都被放在Github上開源、并且經(jīng)過一段時(shí)間的編寫和維護(hù),對(duì)Python開發(fā)有一定的幫助,需要的朋友可以參考下2015-03-03
python基于urllib實(shí)現(xiàn)按照百度音樂分類下載mp3的方法
這篇文章主要介紹了python基于urllib實(shí)現(xiàn)按照百度音樂分類下載mp3的方法,涉及Python使用urllib模塊操作頁(yè)面元素的相關(guān)技巧,需要的朋友可以參考下2015-05-05
Python 工具類實(shí)現(xiàn)大文件斷點(diǎn)續(xù)傳功能詳解
用python進(jìn)行大文件下載的時(shí)候,一旦出現(xiàn)網(wǎng)絡(luò)波動(dòng)問題,導(dǎo)致文件下載到一半。如果將下載不完全的文件刪掉,那么又需要從頭開始,如果連續(xù)網(wǎng)絡(luò)波動(dòng),是不是要頭禿了。本文提供斷點(diǎn)續(xù)傳下載工具方法,希望可以幫助到你2021-10-10

