##language:zh #pragma section-numbers off ##含有章节索引导航的 ZPyUG 文章通用模板 <> ## 默许导航,请保留 <> ##startInc = 如何:不重启服务器就更新模块? = == 提问 == {{{ nillfeng reply-to python-cn@googlegroups.com to python-cn`CPyUG`华蟒用户组 date Thu, Dec 11, 2008 at 15:29 subject [CPyUG:73520] 如何不重启服务器 更新模块 }}} 像GAE 那样,更改一个模块后 上传上去,自动就更新了,而不用重启服务. 如何实现? * 我有个想法是,利用linux 2.6 inotify 检测文件 ,比如配置文件 xxx.py 如果改动了 就把xxx del掉 重新 import 是否可行 或者 来个请求就查看 文件的最后修改时间 如果与上次不符 就del 掉 重新import. == 思路 == {{{ 李富荣 reply-to python-cn@googlegroups.com to python-cn@googlegroups.com date Wed, Dec 17, 2008 at 21:39 subject [CPyUG:73952] Re: 如何不重启服务器 更新模块 }}} 找到下面的这些东西,觉得有些思路了。 * http://www.blogjava.net/huanzhugege/archive/2007/03/12/103325.html * http://pyunit.sourceforge.net/notes/reloading.html * http://www.megasolutions.net/python/re-importing-modules-60265.aspx 这个问题有2方面需要解决: * 1. 能解决依赖关系的递归reload。 * 2. 源文件改变触发递归reload动作。 问题二还有待进一步研究(研究python的inotify lib) === 解决依赖关系的reload === 对于问题1,思路如下: * 做一个import的代理,在执行import的时候,维护一个树结构。 * 在某个文件changed_file_name改变时,调用树根的reload方法。 `伪码:` {{{ class Node: children=list_of_Nodes file_name=the_relative_source_file module=the_module_object def reload(self, changed_file_name): reloaded=False for child_node in self.children: reloaded=child_node.reload(changed_file_name) or reloaded if reloaded or self.file_name==changed_file_name: reload(self.module) return True else: return False def import_proxy(...): module=do_the_real_import() make_a_node() find_the_correct_point_in_NodeTree()# TODO: how? append_the_node_into_the_tree() return module def insert_new_node(new_node, file_name_of_parent, root_node): """ Insert new_node into the tree whoes root is root_node. This new_node should be child of the Nodes whoes file name is file_name_of_parent. """ for child in root_node: insert_new_node(new_node, file_name_of_parent, child) if file_name_of_parent == root_node.file_name: root_node.children.append(new_node) }}} === 整顿思路 === 想了各种不同的方案,觉得还是django.utils.autoreload做得不错。 虽然没什么研究成果,但是学到了不少东西。 * inotify * thread * modules * make proxy for builtin functions.`(最重要的收获)` 2008/12/17 Frank.CH {{{ 这四个方法,是语言层次之上的实现方法; 我倒觉得这种控制,可以放置语言内部实现上; PVM给定对应的参数实现不同的策略更改; 或许这样处理更好; }}} 期待有好的办法彻底解决Reload问题; 把阶段性的研究结果小结一下: 1. 在代码层的实现:: django: * 原理:django的django/utils/autoreload.py是用`os.P_WAIT`模式spawn一个子进程,在新进程中,把开发用的server放到一个thread中跑,在主线程中运行一个循环,检测`sys.__modules__`中被加载的文件的mtime。如果发现文件更改了,就sys.exit(3), server线程自然也就跟着退出。父进程进程检查子进程的exit code, 如果是3,就继续spawn,如此循环下去。 * 使用方法: {{{#!python from django.utils import autoreload autoreload.main(your_server_func, args_for_your_func, kwargs_for_your_func) }}} * 前提:你的development server在一个method里,且能在线程中跑。 '''pyunit:''' * 覆盖`__import__`, 记录下模块的信息,在需要重新运行test的时候,把这些已加载的模块删除,然后运行test。 * pyunit的roll back importer带来的灵感: * 可以覆盖`__builtin __.__import__`方法, * 记录下模块加载的依赖关系。当改变某个文件的时候,根据依赖关系,reload。 * 这种方法缺点是:只能重新加载模块,但对于已经创建的对象,则无能为力了。 '''mod_python的AutoReload''': * 因为自己没用过mod_python,也就没仔细看。 * 粗看了一下,似乎如果autoreloa设成True,在每个request到来的时候,重新加在模块,以及包含该模块的包。 * 但是从mod_python-3.3.1来看,似乎没有处理包之间互相加载的情况。 * 可能是mod_python设计就是一个模块能处理一个request? `---怎样在代码层实现,与应用的环境有关系。` 2. 在代码外面来弄:: * 可以用inotify监测某个文件夹,如果改变了,就运行服务器的重启命令。 * 优点是通用性好,而且服务器运行环境也不改变。 * 缺点是效率不高。 3. 里应外合:: * `里:`不监视文件夹下的所有文件,而是做一个import代理,在服务器启动的时候运行这个代理。 * 这样,服务器就能把自己加载了哪些文件告诉外界了。 * `外:`用inotify,检测服务器所用到的文件的改变情况。 * 这种方法通用性也不错,效率比上面得应该好一些,因为检测的文件不那么多。 4. 编译器 * 我不是科班出身,对这么高深的东西,还有待学习。 * 不过我的想法是,运行程序的时候,真的一条一条去解释。这样就能完全与代码同步了。 * 缺点应该是运行效率问题,但是也许可以用在开发环境也说不定。 * 目前我没找到有这种功能的python解释器。我也不知道cpython会不会有这样的选项。 我正在尝试"里应外合"的方法。如果有人有兴趣,欢迎一起讨论! ##endInc ---- '''反馈'''