2019独角兽企业重金招聘Python工程师标准>>>

这两天在看bottle的时候,发现它也有代码auto reload的功能,就到它的源码中看了一下。

当设置reloader=True的时候,主进程不会启动bottle服务,而是使用与主进程启动时相同的命令行参数创建一个新的子进程。然后主进程不断忙等待子进程结束,拿到子进程的return code,如果子进程返回的code为3,则重新以相同的命令行参数重新启动子进程,之前的代码的改动就被重新reload了。在子进程中,主线程在跑bottle的服务,另外一个线程在不断的check所有import的module文件是否修改(check原理之后会在代码中看到),如果检测到文件的改动,check线程会发送一个KeyboardInterrupt exception到主线程,kill掉bottle的服务,然后子进程以returncode=3退出。

在bottle源码中,autoreload功能主要涉及两个地方一个是run函数,另外一个是FileCheckerThread类。

先看一下run函数部分的代码片段(reloader部分带注释的bottle源码 :https://github.com/kagxin/recipes/blob/master/bottle/bottle.py)。

reloader 为True是开启autoreload功能

    if reloader and not os.environ.get('BOTTLE_CHILD'):  # reloader 为True,且环境变量中的BOTTLE_CHILD没有设置的时候,执行reloader创建新的子进程的逻辑import subprocesslockfile = Nonetry:fd, lockfile = tempfile.mkstemp(prefix='bottle.', suffix='.lock')  # 临时文件是唯一的os.close(fd)  # We only need this file to exist. We never write to itwhile os.path.exists(lockfile):args = [sys.executable] + sys.argv  # 拿到完整的命令行参数environ = os.environ.copy()environ['BOTTLE_CHILD'] = 'true'environ['BOTTLE_LOCKFILE'] = lockfile  # 设置两个环境变量print(args, lockfile)p = subprocess.Popen(args, env=environ)  # 子进程的环境变量中,BOTTLE_CHILD设置为true字符串,这子进程不会再进入if reloader and not os.environ.get('BOTTLE_CHILD') 这个分支,而是执行之后分支开启bottle服务器while p.poll() is None:  # Busy wait...  等待运行bottle服务的子进程结束os.utime(lockfile, None)  # I am alive!  更新lockfile文件,的access time 和 modify timetime.sleep(interval)if p.poll() != 3:if os.path.exists(lockfile): os.unlink(lockfile)sys.exit(p.poll())except KeyboardInterrupt:passfinally:if os.path.exists(lockfile):  # 清楚lockfileos.unlink(lockfile)return......

代码分析:

程序执行,当reloader为True而且环境变量中没有BOTTLE_CHILD的时候,执行之后逻辑,BOTTLE_CHILD这个环境变量是用来的在Popen使用命令行参数启动子进程的时候,让启动的子进程不要进入当前分支,而是直接执行之后启动bottle服务的逻辑。

先不要关注lockfile文件,它的主要作用是让子进程通过判断它的modify time是否更新,来判断主进程是否依然存活。while p.poll() is None:... 这段代码是在忙等待子进程结束,同时使用os.utime不断更新lockfile的aceess time和modify time。如果returncode==3说明子进程因文件修改而结束,则在当前循环中通过popen使用相同的命令行重新启动子进程。

    if reloader:lockfile = os.environ.get('BOTTLE_LOCKFILE')bgcheck = FileCheckerThread(lockfile, interval)  # 在当前进程中,创建用于check文件改变的线程with bgcheck:  # FileCheckerThread 实现了,上下文管理器协议, server.run(app)if bgcheck.status == 'reload':  # 监控的module文件发生改变,以returncode=3退出子进程,父进程会拿到这个returncode重新启动一个子进程,即bottle服务进程sys.exit(3)else:server.run(app)

代码分析:

这个是子进程中的主体部分,在bgcheck这上下文管理器中,运行bottle服务,server.run(app)是阻塞的直到收到主线程结束信号。在这个上下文管理器中,运行着一个check文件改动的线程。如果文件改动就会向当前主线程发送KeyboardInterrupt终止server.run(app)。上下文管理器退出时会忽略这个KeyboardInterrupt异常,然后以returncode==3退出子进程。

class FileCheckerThread(threading.Thread):""" Interrupt main-thread as soon as a changed module file is detected,the lockfile gets deleted or gets too old. """def __init__(self, lockfile, interval):threading.Thread.__init__(self)self.daemon = Trueself.lockfile, self.interval = lockfile, interval#: Is one of 'reload', 'error' or 'exit'self.status = Nonedef run(self):exists = os.path.existsmtime = lambda p: os.stat(p).st_mtimefiles = dict()for module in list(sys.modules.values()):path = getattr(module, '__file__', '')if path[-4:] in ('.pyo', '.pyc'): path = path[:-1]if path and exists(path): files[path] = mtime(path)  # 拿到所有导入模块文件的modify timewhile not self.status:if not exists(self.lockfile)\or mtime(self.lockfile) < time.time() - self.interval - 5:self.status = 'error'thread.interrupt_main()for path, lmtime in list(files.items()):if not exists(path) or mtime(path) > lmtime:  # 如果文件发生改动,self.status = 'reload'thread.interrupt_main()  # raise 一个 KeyboardInterrupt exception in 主线程break time.sleep(self.interval)def __enter__(self):self.start()def __exit__(self, exc_type, *_):if not self.status: self.status = 'exit'  # silent exitself.join()return exc_type is not None and issubclass(exc_type, KeyboardInterrupt)

代码分析:

这个类有__enter__和__exit__这两个dunder方法,实现了上下文管理器协议。在进入这个上下文管理器的时候,启动这个线程,退出时等待线程结束,且忽略了KeyboardInterrupt异常,因为__exit__返回True之外的值时,with中的异常才会向上冒泡。

在run方法中在for module in list(sys.modules.values()):...这个for循环中拿到所有module文件的modify time。然后在之后的while循环中,监测文件改动,如果有改动调用thread.interrupt_main(),在主线程(bottle所在线程)中raise,KeyboardInterrupt异常。

上面就是整个bottle auto reload机制的代码。

reloader部分带注释的bottle源码 :

https://github.com/kagxin/recipes/blob/master/bottle/bottle.py

欢迎拍砖砖交流╭(╯^╰)╮

转载于:https://my.oschina.net/u/2255341/blog/1626524

python web框架autoreload原理(以bottle为例)相关推荐

  1. Python Web框架

    Bottle: Python Web框架中文文档 Bottle是一个快速,简单,轻量级的 Python WSGI Web框架.单一文件,只依赖 Python标准库 . URL映射(Routing): ...

  2. 微型 Python Web 框架: Bottle

    微型 Python Web 框架: Bottle 在 19/09/11 07:04 PM 由 COSTONY 发表 Bottle 是一个非常小巧但高效的微型 Python Web 框架,它被设计为仅仅 ...

  3. python bottle框架 重定向_微型 Python Web 框架: Bottle

    Bottle 是一个非常小巧但高效的微型 Python Web 框架,它被设计为仅仅只有一个文件的Python模块,并且除Python标准库外,它不依赖于任何第三方模块. 路由(Routing):将请 ...

  4. 微型 Python Web 框架 Bottle - Heroin blog

    微型 Python Web 框架 Bottle - Heroin blog 微型 Python Web 框架 Bottle

  5. python web框架介绍对比

    Django Python框架虽然说是百花齐放,但仍然有那么一家是最大的,它就是Django.要说Django是Python框架里最好的,有人同意也有人 坚决反对,但说Django的文档最完善.市场占 ...

  6. python写web难受-(2017)你最不建议使用的Python Web框架?

    原标题:(2017)你最不建议使用的Python Web框架? 前言 这是一篇发在知乎专栏的文章,内容是之前我提的「(2017)你最不建议使用的Python Web框架?」下的回答.不过有些话没有说完 ...

  7. python的web框架哪个最好学_2018年要学习的10大Python Web框架

    通过为开发人员提供应用程序开发结构,框架使开发人员的生活更轻松.他们自动执行通用解决方案,缩短开发时间,并允许开发人员更多地关注应用程序逻辑而不是常规元素. 在本文中,我们分享了我们自己的前十大Pyt ...

  8. python web 框架例子_最快的 Python Web 框架入门

    原标题:最快的 Python Web 框架入门 来源:Python开发 ID:PythonPush 速度比较 框架 实现基础 每秒请求数 平均时间 Sanic Python 3.5 + uvloop ...

  9. 第9章 Python Web 框架考察点

    Python WSGI与web框架常考点 WSGI 常见Web框架 ◆什么是WSGI? ◆常用的 Python Web框架Dang/Fask/Tornado对比 ◆web框架的组成(淡化框架,加强基础 ...

最新文章

  1. 轻松掌握mysql数据库锁机制的相关原理_轻松掌握MySQL数据库锁机制的相关原理...
  2. 2018年中国高被引学者榜单发布,清华入榜学者数位列高校第一
  3. linux应用程序接收文件,Linux应用程序学习之文件编程
  4. Struts2请求处理的内部流程说明(版本二)
  5. 局域网ssr转pptp_[网络技术][转]PPTP连接过程
  6. php model controller,Laravel 中 Controller访问Model函数/常量
  7. JS 类数组,字符串,转换成数组的方法
  8. Linux下互斥量加锁与解锁操作的C代码实现
  9. 【JAVA笔记——器】Spring MVC + HATEOAS RestFul快速搭建
  10. 一元函数积分学的概念与性质
  11. 荣耀MagicBook X桌面频繁蓝屏如何重装系统?
  12. lnoi2019游记
  13. 你为什么选择计算机这个专业英语,英文作文:为什么选择计算机作为你的专业...
  14. 楚留香手游系统互通的服务器,楚留香手游帮派系统互通介绍
  15. 《算法4》读书笔记(一)
  16. python绘制社会关系网络图_python networkx 包绘制复杂网络关系图的实现
  17. kali安装python gui_黄聪:史上最详细的kali安装教程没有之一
  18. Numpy属性dtype的转换(数据类型转换):unit8和float32转换
  19. 支持MOC的协议(不大好使呀)
  20. 最大公约数和最小公倍数系列

热门文章

  1. 计算机会计应用实训,计算机会计模拟实习报告.pdf
  2. linux目录为root所有文件,linux获取文件所有目录/文件夹的例子linux操作系统 -电脑资料...
  3. java远程线程注入_系统权限远程线程注入到Explorer.exe
  4. python模拟内置函数reversed_Python内置函数reversed
  5. java uml 类图 加号_UML建模基础 UML类图的组成元素和关系解析
  6. icc校色文件使用教程_Flink教程-flink 1.11使用sql将流式数据写入文件系统
  7. 离散数学专业术语(continuous updating)
  8. 从零开始学习PYTHON3讲义(一)认识Python
  9. 7系列高速收发器总结 GTP IP核使用篇
  10. LruCache缓存处理及异步加载图片类的封装