django的autoreload机制实现


Posted in Python onJune 03, 2020

在开发django应用的过程中,使用开发者模式启动服务是特别方便的一件事,只需要 python manage.py runserver 就可以运行服务,并且提供了非常人性化的autoreload机制,不需要手动重启程序就可以修改代码并看到反馈。

源码分析:

runserver命令

命令行键入 python manage.py runserver 后,django会去寻找runserver这个命令的执行模块,最后落在 django\contrib\staticfiles\management\commands\runserver.py模块上:

def run(self, **options):
  """
  Runs the server, using the autoreloader if needed
  """
  use_reloader = options['use_reloader']
 
  if use_reloader:
   autoreload.main(self.inner_run, None, options)
  else:
   self.inner_run(None, **options)

autoreload模块。看autoreload.main():

django\utils\autoreload.py:

这里有关于use_reloader的判断。如果我们在启动命令中没有加--noreload,程序就会走autoreload.main这个函数,如果加了,就会走self.inner_run,直接启动应用。 其实从autoreload.main的参数也可以看出,它应该是对self.inner_run做了一些封装,autoreload的机制就在这些封装当中,下面我们继续跟。

def main(main_func, args=None, kwargs=None):
 if args is None:
  args = ()
 if kwargs is None:
  kwargs = {}
 if sys.platform.startswith('java'):
  reloader = jython_reloader
 else:
  reloader = python_reloader
 
 wrapped_main_func = check_errors(main_func)
 reloader(wrapped_main_func, args, kwargs)

这里针对jpython和其他python做了区别处理,先忽略jpython;check_errors就是把对main_func进行错误处理,也先忽略。看python_reloader:

def python_reloader(main_func, args, kwargs):
 if os.environ.get("RUN_MAIN") == "true":
  thread.start_new_thread(main_func, args, kwargs)
  try:
   reloader_thread()
  except KeyboardInterrupt:
   pass
 else:
  try:
   exit_code = restart_with_reloader()
   if exit_code < 0:
    os.kill(os.getpid(), -exit_code)
   else:
    sys.exit(exit_code)
  except KeyboardInterrupt:
   pass

第一次走到这里时候,环境变量中RUN_MAIN变量不是"true", 甚至都没有,所以走else, 看restart_with_reloader:

#django\utils\autoreload.py:
def restart_with_reloader():
 while True:
 args = [sys.executable] + ['-W%s' % o for o in sys.warnoptions] + sys.argv


if sys.platform == "win32":



args = ['"%s"' % arg for arg in args]


new_environ = os.environ.copy()


new_environ["RUN_MAIN"] = 'true'


exit_code = os.spawnve(os.P_WAIT, sys.executable, args, new_environ)


if exit_code != 3:



return exit_code

这里首先起一个while循环, 内部先把RUN_MAIN改成了"true",然后用os.spawnve方法开一个子进程(subprocess), 其实就是再调一遍命令行,又走了一遍 python manage.py runserver。

接着看restart_with_reloader里的while循环,需要注意的是while循环退出的唯一条件是exit_code!=3。 如果子进程不退出,就一直停在 os.spawnve这一步; 如果子进程退出,而退出码不是3,while就被终结了;如果是3,继续循环,重新创建子进程。从这个逻辑可以猜想autoreload的机制:当前进程(主进程)其实啥也不干,就监视子进程的运行状况,子进程才是真正干事儿的;如果子进程以exit_code=3退出(应该由于检测到了文件修改),就再启动一遍子进程,新代码自然就生效了;如果子进程以exit_code!=3退出,主进程也结束,整个django程序就算跪了。这只是猜想,下面接着来验证。

子进程。上面其实有一个疑问,既然是重新启动了一次,为什么子进程不会接着生成子进程?原因就在于RUN_MAIN这个环境变量,主进程中把它改成了true,子进程走到python_reloader函数的时候:

#django\utils\autoreload.py:
def python_reloader(main_func, args, kwargs):
if os.environ.get("RUN_MAIN") == "true":


thread.start_new_thread(main_func, args, kwargs)


try:



reloader_thread()


except KeyboardInterrupt:



pass

else:


try:



exit_code = restart_with_reloader()



if exit_code < 0:




os.kill(os.getpid(), -exit_code)



else:




sys.exit(exit_code)


except KeyboardInterrupt:



pass

if条件满足了,和主进程走了不一样的逻辑分支。在这里,首先去开一个线程,运行main_func,就是上文的 Command.inner_run。这里的thread模块是这么import的:

然后再开一个reloader_thread:

def reloader_thread():
 ensure_echo_on()
 if USE_INOTIFY:
  fn = inotify_code_changed
 else:
  fn = code_changed
 while RUN_RELOADER:
  change = fn()
  if change == FILE_MODIFIED:
   sys.exit(3) # force reload
  elif change == I18N_MODIFIED:
   reset_translations()
  time.sleep(1)

ensure_echo_on()其实还没看明白,貌似是针对类unix系统文件处理的,先略过; USE_INOTIFY也是系统文件操作相关的变量,根据 inotify 是否可用选择检测文件变化的方法。 while循环,每隔1秒检测一下文件状态,如果是普通文件有变化,进程退出,退出码为3,主进程一看:退出码是3,就重启子进程。。。。这样就和上面连上了;如果不是普通文件变化,而是I18N_MODIFIED(.mo后缀的文件变化,二进制库文件之类的),那就 reset_translations ,大概意思是把已加载过的库缓存清理掉,下次重新加载。

以上就是autoreload机制的流程。其中还是有些细节不是特别清楚,比如不同操作系统文件变化的检测,但都是很细节的东西了,不涉及主流程。看完这些,我又问了自己一遍,如果是让我设计autoreload机制会怎样搞。现在我的答案是:直接把 django\utils\autoreload.py 文件拿来用啊。其实这是很独立的一个模块,而且特别通用,完全可以作为通用的autoreload解决方案。

到此这篇关于django的autoreload机制实现的文章就介绍到这了,更多相关django autoreload内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python数据分析之如何利用pandas查询数据示例代码
Sep 01 Python
python网络爬虫学习笔记(1)
Apr 09 Python
Python用于学习重要算法的模块pygorithm实例浅析
Aug 16 Python
基于PyQt4和PySide实现输入对话框效果
Feb 27 Python
PySide和PyQt加载ui文件的两种方法
Feb 27 Python
Python中函数参数匹配模型详解
Jun 09 Python
关于阿里云oss获取sts凭证 app直传 python的实例
Aug 20 Python
pytorch 实现查看网络中的参数
Jan 06 Python
pytorch的batch normalize使用详解
Jan 15 Python
对tensorflow 中tile函数的使用详解
Feb 07 Python
python实现信号时域统计特征提取代码
Feb 26 Python
深度学习小工程练习之垃圾分类详解
Apr 14 Python
浅谈python量化 双均线策略(金叉死叉)
Jun 03 #Python
Django用户登录与注册系统的实现示例
Jun 03 #Python
python 瀑布线指标编写实例
Jun 03 #Python
Django微信小程序后台开发教程的实现
Jun 03 #Python
python判断正负数方式
Jun 03 #Python
Python绘制动态水球图过程详解
Jun 03 #Python
解决numpy矩阵相减出现的负值自动转正值的问题
Jun 03 #Python
You might like
为PHP安装imagick时出现Cannot locate header file MagickWand.h错误的解决方法
2014/11/03 PHP
PHP简单遍历对象示例
2016/09/28 PHP
PHP抽象类和接口用法实例详解
2019/07/20 PHP
jQuery插件 selectToSelect使用方法
2013/10/02 Javascript
js检测浏览器版本、核心、是否移动端示例
2014/04/24 Javascript
JS中使用sort结合localeCompare实现中文排序实例
2014/07/23 Javascript
javascript实现修改微信分享的标题内容等
2014/12/11 Javascript
jquery图片播放浏览插件prettyPhoto使用详解
2014/12/19 Javascript
JavaScript父子窗体间的调用方法
2015/03/31 Javascript
javascript动态创建链接的方法
2015/05/13 Javascript
JavaScript使用FileSystemObject对象写入文本文件内容的方法
2015/08/05 Javascript
Bootstrap实现带动画过渡的弹出框
2016/08/09 Javascript
vue使用Font Awesome的方法步骤
2019/02/26 Javascript
通过循环优化 JavaScript 程序
2019/06/24 Javascript
js实现的格式化数字和金额功能简单示例
2019/07/30 Javascript
Vue中axios的封装(报错、鉴权、跳转、拦截、提示)
2019/08/20 Javascript
利用d3.js制作连线动画图与编辑器的方法实例
2019/09/05 Javascript
python中精确输出JSON浮点数的方法
2014/04/18 Python
Python批量创建迅雷任务及创建多个文件
2016/02/13 Python
python利用dir函数查看类中所有成员函数示例代码
2017/09/08 Python
django上传图片并生成缩略图方法示例
2017/12/11 Python
Python实现图片转字符画的代码实例
2019/02/22 Python
Python通过递归获取目录下指定文件代码实例
2019/11/07 Python
Python常见反爬虫机制解决方案
2020/06/01 Python
Python dict的常用方法示例代码
2020/06/23 Python
详解使用scrapy进行模拟登陆三种方式
2021/02/21 Python
用html5的canvas和JavaScript创建一个绘图程序的简单实例
2016/07/06 HTML / CSS
美国女性服饰销售网站:Nasty Gal(坏女孩)
2016/07/26 全球购物
大学生水文观测实习自我鉴定
2013/09/29 职场文书
英语专业推荐信
2013/11/16 职场文书
考博专家推荐信
2014/05/10 职场文书
2014年毕业演讲稿范文
2014/05/13 职场文书
廉洁家庭事迹材料
2014/05/15 职场文书
乡镇干部先进性教育活动个人整改措施
2014/09/16 职场文书
windows11选中自动复制怎么开启? Win11自动复制所选内容的方法
2022/07/23 数码科技
新的CSS 伪类函数 :is() 和 :where()示例详解
2022/08/05 HTML / CSS