Tornado Application对象实例化时"debug=Ture"参数的作用原理
来源:互联网 发布:有什么金融软件 编辑:程序博客网 时间:2024/06/06 00:00
当我们在使用Tornado框架编写程序的时候,使用Tornado自带的调试模式可以让我们的工作轻松不少。因为这样我们就不必要在每次修改程序后手动重启服务器。
开启Tornado的方法就是在实例化Application对象的时候加入"debug=True"参数,示例代码:
app = tornado.web.Application( handlers=[(r'/', IndexHandler)], debug=True)
那么,加入"debug=True"参数后代码实现自动编译的原理是什么呢?查看Tornado web.py的源代码,找到Application类的定义,我们看到Application类的构造函数:
def __init__(self, handlers=None, default_host="", transforms=None, **settings)其中:
if self.settings.get('debug'): self.settings.setdefault('autoreload', True) self.settings.setdefault('compiled_template_cache', False) self.settings.setdefault('static_hash_cache', False) self.settings.setdefault('serve_traceback', True)# Automatically reload modified modulesif self.settings.get('autoreload'): from tornado import autoreload autoreload.start()可以知道,如果我们在Application实例化的时候加入"debug=True"参数,程序import了autoreload模块,并且调用了autoreload.start()函数来实现自动重载。事实上,我们可以有开启Tornado调试模式的第二种写法:
import tornado.autoreloadapp = tornado.web.Application( handlers=[(r'/', IndexHandler)])http_server = tornado.httpserver.HTTPServer(app)http_server.listen(options.port)instance = tornado.ioloop.IOLoop.instance()tornado.autoreload.start(instance)instance.start()现在,我们来看一下,autoreload.start()又是如何实现程序的自动重载的。
查看Tornado的autoreload.py文件,看到start函数:
def start(io_loop=None, check_time=500): """Begins watching source files for changes using the given `.IOLoop`. """ io_loop = io_loop or ioloop.IOLoop.current() if io_loop in _io_loops: return _io_loops[io_loop] = True if len(_io_loops) > 1: gen_log.warning("tornado.autoreload started more than once in the same process") add_reload_hook(functools.partial(io_loop.close, all_fds=True)) modify_times = {} callback = functools.partial(_reload_on_update, modify_times) scheduler = ioloop.PeriodicCallback(callback, check_time, io_loop=io_loop) scheduler.start()函数的功能注释已经写得很清楚了,就是循环监视 '.IOLoop'的源文件,默认时间500ms。这个函数通过使用PeriodicCallback类实例化一个scheduler对象,并且根据PeriodicCallback的特性循环调用一个callback函数。而callback函数则是由偏函数functools.partial以函数_reload_on_update, 集合modify_times为参数生成的(函数式编程的思想)。
查看_reload_on_update的源代码:
def _reload_on_update(modify_times): if _reload_attempted: # We already tried to reload and it didn't work, so don't try again. return if process.task_id() is not None: # We're in a child process created by fork_processes. If child # processes restarted themselves, they'd all restart and then # all call fork_processes again. return for module in sys.modules.values(): # Some modules play games with sys.modules (e.g. email/__init__.py # in the standard library), and occasionally this can cause strange # failures in getattr. Just ignore anything that's not an ordinary # module. if not isinstance(module, types.ModuleType): continue path = getattr(module, "__file__", None) if not path: continue if path.endswith(".pyc") or path.endswith(".pyo"): path = path[:-1] _check_file(modify_times, path) for path in _watched_files: _check_file(modify_times, path)
它用_check_file函数检查sys.modules里的各种py文件,如果文件的os.stat时间戳改变,那么就执行_reload()重新编译加载,_check_file函数代码:
def _check_file(modify_times, path): try: modified = os.stat(path).st_mtime except Exception: return if path not in modify_times: modify_times[path] = modified return if modify_times[path] != modified: gen_log.info("%s modified; restarting server", path) _reload()
这里,modified = os.stat(path).st_mtime就是获取路径为path的文件最后被修改的时间。
#一个使用os.stat来获取文件创建时间和最近修改时间的小例子import osimport timestat = os.stat(path)print "%s" % time.ctime(stat.st_ctime)print "%s" % time.ctime(stat.st_mtime)
通过比较在这一次循环中文件的st_mtime与上次循环的st_mtime,来发现文件是否被修改过。如果发现有文件被修改,就restarting server。看到_reload()函数的源代码:
def _reload(): global _reload_attempted _reload_attempted = True for fn in _reload_hooks: fn() if hasattr(signal, "setitimer"): # Clear the alarm signal set by # ioloop.set_blocking_log_threshold so it doesn't fire # after the exec. signal.setitimer(signal.ITIMER_REAL, 0, 0) # sys.path fixes: see comments at top of file. If sys.path[0] is an empty # string, we were (probably) invoked with -m and the effective path # is about to change on re-exec. Add the current directory to $PYTHONPATH # to ensure that the new process sees the same path we did. path_prefix = '.' + os.pathsep if (sys.path[0] == '' and not os.environ.get("PYTHONPATH", "").startswith(path_prefix)): os.environ["PYTHONPATH"] = (path_prefix + os.environ.get("PYTHONPATH", "")) if sys.platform == 'win32': # os.execv is broken on Windows and can't properly parse command line # arguments and executable name if they contain whitespaces. subprocess # fixes that behavior. subprocess.Popen([sys.executable] + sys.argv) sys.exit(0) else: try: os.execv(sys.executable, [sys.executable] + sys.argv) except OSError: # Mac OS X versions prior to 10.6 do not support execv in # a process that contains multiple threads. Instead of # re-executing in the current process, start a new one # and cause the current process to exit. This isn't # ideal since the new process is detached from the parent # terminal and thus cannot easily be killed with ctrl-C, # but it's better than not being able to autoreload at # all. # Unfortunately the errno returned in this case does not # appear to be consistent, so we can't easily check for # this error specifically. os.spawnv(os.P_NOWAIT, sys.executable, [sys.executable] + sys.argv) sys.exit(0)_USAGE = """\Usage: python -m tornado.autoreload -m module.to.run [args...] python -m tornado.autoreload path/to/script.py [args...]"""
在这个函数中,先执行了_reload_hooks中的函数,也就是ioloop.close,然后对文件的路径进行了判断和相关操作,再判断操作系统,如果sys.platform 为'win32'的话,就执行subprocess.Popen([sys.executable] + sys.argv)进行重载,否则行os.spawnv(os.P_NOWAIT, sys.executable, [sys.executable] + sys.argv)进行重载。
以上大致就是"debug=True"参数的作用原理了。我在解析的过程中,只是简单的根据源码来一步一步追踪 'debug=True'加入后被执行到的函数,由于本人知识水平有限,理解难免有疏漏甚至错误的地方,希望各位多多包涵并为我指出错漏。
附上tornado.autoreload、tornado.ioloop.PeriodicCallback的源码以及几个相关博客链接:
tornado.autoreload
tornado.ioloop.PeriodicCallback
python os.stat() 和 stat模块详解
玩蛇记-使用Tornado构建高性能Web之二-autoreload
- Tornado Application对象实例化时"debug=Ture"参数的作用原理
- QTP针对对象的参数化实例
- 数组元素实例化对象的原理
- tornado中参数的获取
- Tornado"debug=True"动态编译
- 可变参数宏的原理及作用
- HashCode的作用原理和实例解析
- HashCode的作用原理和实例解析
- HashCode的作用原理和实例解析
- HashCode的作用原理和实例解析
- 7.Application对象的接口与起到的作用---Application对象工作机制
- JSP基础知识(application和内置对象的作用范围)
- 关于set sql_trace=ture 的一些用法
- 可变参数函数的原理与实例
- Application.DoEvents()的作用
- Application.DoEvents()的作用
- Android Application的作用
- Android Application的作用
- 拌面
- Android通知MediaScanner扫描指定的文件
- HDU 1232
- HDU 1530 Maximum Clique 图论最大团问题
- NSObject类别-NSThreadPerformAdditions
- Tornado Application对象实例化时"debug=Ture"参数的作用原理
- 深搜hdu1312
- 数据类型和循环结构第二天
- 指针和引用
- java命令执行jar包的方式
- MFC绘图控制-设备描述表
- R语言统计分析篇
- C#处理Json文件
- HDU4772(杭州赛区)