Differences between revisions 2 and 3
Revision 2 as of 2009-10-17 06:11:52
Size: 6278
Editor: limodou
Comment:
Revision 3 as of 2009-12-25 07:19:10
Size: 6278
Editor: localhost
Comment: converted to 1.6 markup
Deletions are marked like this. Additions are marked like this.
Line 4: Line 4:
[[TableOfContents]] <<TableOfContents>>
Line 6: Line 6:
[[Include(ZPyUGnav)]] <<Include(ZPyUGnav)>>

如何:不重启服务器就更新模块?

提问

nillfeng <[email protected]>
reply-to        [email protected]
to      python-cn`CPyUG`华蟒用户组 <[email protected]>
date    Thu, Dec 11, 2008 at 15:29
subject [CPyUG:73520] 如何不重启服务器 更新模块

像GAE 那样,更改一个模块后 上传上去,自动就更新了,而不用重启服务. 如何实现?

  • 我有个想法是,利用linux 2.6 inotify 检测文件 ,比如配置文件 xxx.py 如果改动了 就把xxx del掉 重新 import

是否可行 或者 来个请求就查看 文件的最后修改时间 如果与上次不符 就del 掉 重新import.

思路

李富荣 <[email protected]>
reply-to        [email protected]
to      [email protected]
date    Wed, Dec 17, 2008 at 21:39
subject [CPyUG:73952] Re: 如何不重启服务器 更新模块

找到下面的这些东西,觉得有些思路了。

这个问题有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 <[email protected]>

    这四个方法,是语言层次之上的实现方法;
    我倒觉得这种控制,可以放置语言内部实现上; 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,如此循环下去。

    • 使用方法:

   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?

---怎样在代码层实现,与应用的环境有关系。

  1. 在代码外面来弄::
    • 可以用inotify监测某个文件夹,如果改变了,就运行服务器的重启命令。
    • 优点是通用性好,而且服务器运行环境也不改变。
    • 缺点是效率不高。
  2. 里应外合::
    • 里:不监视文件夹下的所有文件,而是做一个import代理,在服务器启动的时候运行这个代理。

      • 这样,服务器就能把自己加载了哪些文件告诉外界了。
    • 外:用inotify,检测服务器所用到的文件的改变情况。

    • 这种方法通用性也不错,效率比上面得应该好一些,因为检测的文件不那么多。
  3. 编译器
    • 我不是科班出身,对这么高深的东西,还有待学习。
    • 不过我的想法是,运行程序的时候,真的一条一条去解释。这样就能完全与代码同步了。
    • 缺点应该是运行效率问题,但是也许可以用在开发环境也说不定。
    • 目前我没找到有这种功能的python解释器。我也不知道cpython会不会有这样的选项。

我正在尝试"里应外合"的方法。如果有人有兴趣,欢迎一起讨论!


反馈

MiscItems/2008-12-17 (last edited 2009-12-25 07:19:10 by localhost)