Contents
如何:不重启服务器就更新模块?
提问
nillfeng <fengshihao@hotmail.com> reply-to python-cn@googlegroups.com to python-cn`CPyUG`华蟒用户组 <python-cn@googlegroups.com> date Thu, Dec 11, 2008 at 15:29 subject [CPyUG:73520] 如何不重启服务器 更新模块
像GAE 那样,更改一个模块后 上传上去,自动就更新了,而不用重启服务. 如何实现?
- 我有个想法是,利用linux 2.6 inotify 检测文件 ,比如配置文件 xxx.py 如果改动了 就把xxx del掉 重新 import
是否可行 或者 来个请求就查看 文件的最后修改时间 如果与上次不符 就del 掉 重新import.
思路
李富荣 <leefurong@gmail.com> 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://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 <lovecjavapython@gmail.com>
这四个方法,是语言层次之上的实现方法; 我倒觉得这种控制,可以放置语言内部实现上; PVM给定对应的参数实现不同的策略更改; 或许这样处理更好;
- 期待有好的办法彻底解决Reload问题;
把阶段性的研究结果小结一下:
- 在代码层的实现:: django:
原理:django的django/utils/autoreload.py是用os.P_WAIT模式spawn一个子进程,在新进程中,把开发用的server放到一个thread中跑,在主线程中运行一个循环,检测sys.__modules__中被加载的文件的mtime。如果发现文件更改了,就sys.exit(3), server线程自然也就跟着退出。父进程进程检查子进程的exit code, 如果是3,就继续spawn,如此循环下去。
- 使用方法:
1 from django.utils import autoreload
2 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?
---怎样在代码层实现,与应用的环境有关系。
- 在代码外面来弄::
- 可以用inotify监测某个文件夹,如果改变了,就运行服务器的重启命令。
- 优点是通用性好,而且服务器运行环境也不改变。
- 缺点是效率不高。
- 里应外合::
里:不监视文件夹下的所有文件,而是做一个import代理,在服务器启动的时候运行这个代理。
- 这样,服务器就能把自己加载了哪些文件告诉外界了。
外:用inotify,检测服务器所用到的文件的改变情况。
- 这种方法通用性也不错,效率比上面得应该好一些,因为检测的文件不那么多。
- 编译器
- 我不是科班出身,对这么高深的东西,还有待学习。
- 不过我的想法是,运行程序的时候,真的一条一条去解释。这样就能完全与代码同步了。
- 缺点应该是运行效率问题,但是也许可以用在开发环境也说不定。
- 目前我没找到有这种功能的python解释器。我也不知道cpython会不会有这样的选项。
我正在尝试"里应外合"的方法。如果有人有兴趣,欢迎一起讨论!
反馈