用Python实现服务器中只重载被修改的进程的方法


Posted in Python onApril 30, 2015

现在,我们已经把一个Web App的框架完全搭建好了,从后端的API到前端的MVVM,流程已经跑通了。

在继续工作前,注意到每次修改Python代码,都必须在命令行先Ctrl-C停止服务器,再重启,改动才能生效。

在开发阶段,每天都要修改、保存几十次代码,每次保存都手动来这么一下非常麻烦,严重地降低了我们的开发效率。有没有办法让服务器检测到代码修改后自动重新加载呢?

Django的开发环境在Debug模式下就可以做到自动重新加载,如果我们编写的服务器也能实现这个功能,就能大大提升开发效率。

可惜的是,Django没把这个功能独立出来,不用Django就享受不到,怎么办?

其实Python本身提供了重新载入模块的功能,但不是所有模块都能被重新载入。另一种思路是检测www目录下的代码改动,一旦有改动,就自动重启服务器。

按照这个思路,我们可以编写一个辅助程序pymonitor.py,让它启动wsgiapp.py,并时刻监控www目录下的代码改动,有改动时,先把当前wsgiapp.py进程杀掉,再重启,就完成了服务器进程的自动重启。

要监控目录文件的变化,我们也无需自己手动定时扫描,Python的第三方库watchdog可以利用操作系统的API来监控目录文件的变化,并发送通知。我们先用easy_install安装:

$ easy_install watchdog

利用watchdog接收文件变化的通知,如果是.py文件,就自动重启wsgiapp.py进程。

利用Python自带的subprocess实现进程的启动和终止,并把输入输出重定向到当前进程的输入输出中:

#!/usr/bin/env python
import os, sys, time, subprocess

from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

def log(s):
  print '[Monitor] %s' % s

class MyFileSystemEventHander(FileSystemEventHandler):
  def __init__(self, fn):
    super(MyFileSystemEventHander, self).__init__()
    self.restart = fn

  def on_any_event(self, event):
    if event.src_path.endswith('.py'):
      log('Python source file changed: %s' % event.src_path)
      self.restart()

command = ['echo', 'ok']
process = None

def kill_process():
  global process
  if process:
    log('Kill process [%s]...' % process.pid)
    process.kill()
    process.wait()
    log('Process ended with code %s.' % process.returncode)
    process = None

def start_process():
  global process, command
  log('Start process %s...' % ' '.join(command))
  process = subprocess.Popen(command, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr)

def restart_process():
  kill_process()
  start_process()

def start_watch(path, callback):
  observer = Observer()
  observer.schedule(MyFileSystemEventHander(restart_process), path, recursive=True)
  observer.start()
  log('Watching directory %s...' % path)
  start_process()
  try:
    while True:
      time.sleep(0.5)
  except KeyboardInterrupt:
    observer.stop()
  observer.join()

if __name__ == '__main__':
  argv = sys.argv[1:]
  if not argv:
    print('Usage: ./pymonitor your-script.py')
    exit(0)
  if argv[0]!='python':
    argv.insert(0, 'python')
  command = argv
  path = os.path.abspath('.')
  start_watch(path, None)

一共50行左右的代码,就实现了Debug模式的自动重新加载。用下面的命令启动服务器:

$ python pymonitor.py wsgiapp.py

或者给pymonitor.py加上可执行权限,启动服务器:

$ ./pymonitor.py wsgiapp.py

在编辑器中打开一个py文件,修改后保存,看看命令行输出,是不是自动重启了服务器:

$ ./pymonitor.py wsgiapp.py 
[Monitor] Watching directory /Users/michael/Github/awesome-python-webapp/www...
[Monitor] Start process python wsgiapp.py...
...
INFO:root:application (/Users/michael/Github/awesome-python-webapp/www) will start at 0.0.0.0:9000...
[Monitor] Python source file changed: /Users/michael/Github/awesome-python-webapp/www/apis.py
[Monitor] Kill process [2747]...
[Monitor] Process ended with code -9.
[Monitor] Start process python wsgiapp.py...
...
INFO:root:application (/Users/michael/Github/awesome-python-webapp/www) will start at 0.0.0.0:9000...
Try
Python 相关文章推荐
Python性能优化的20条建议
Oct 25 Python
Android应用开发中Action bar编写的入门教程
Feb 26 Python
Python实现可获取网易页面所有文本信息的网易网络爬虫功能示例
Jan 15 Python
python基础教程项目五之虚拟茶话会
Apr 02 Python
使用python将时间转换为指定的格式方法
Nov 12 Python
解决python ogr shp字段写入中文乱码的问题
Dec 31 Python
详解Python中的测试工具
Jun 09 Python
Python3.5以上版本lxml导入etree报错的解决方案
Jun 26 Python
python之拟合的实现
Jul 19 Python
Python如何基于rsa模块实现非对称加密与解密
Jan 03 Python
Python解释器以及PyCharm的安装教程图文详解
Feb 26 Python
Python GUI编程学习笔记之tkinter界面布局显示详解
Mar 30 Python
python同时给两个收件人发送邮件的方法
Apr 30 #Python
python通过邮件服务器端口发送邮件的方法
Apr 30 #Python
在Python的web框架中中编写日志列表的教程
Apr 30 #Python
python登录pop3邮件服务器接收邮件的方法
Apr 30 #Python
python通过smpt发送邮件的方法
Apr 30 #Python
在Python的web框架中编写创建日志的程序的教程
Apr 30 #Python
用Python实现web端用户登录和注册功能的教程
Apr 30 #Python
You might like
php 字符串函数收集
2010/03/29 PHP
php安装swoole扩展的方法
2015/03/19 PHP
10个超级有用的PHP代码片段果断收藏
2015/09/23 PHP
详解WordPress开发中用于获取分类及子页面的函数用法
2016/01/08 PHP
让你的PHP7更快之Hugepage用法分析
2016/05/31 PHP
php图片裁剪函数
2018/10/31 PHP
jquery下利用jsonp跨域访问实现方法
2010/07/29 Javascript
用json方式实现在 js 中建立一个map
2014/05/02 Javascript
js图片卷帘门导航菜单特效代码分享
2015/09/10 Javascript
JS实现可关闭的对联广告效果代码
2015/09/14 Javascript
win7下安装配置node.js+express开发环境
2015/12/06 Javascript
js完整倒计时代码分享
2016/09/18 Javascript
js中通过getElementsByName访问name集合对象的方法
2016/10/31 Javascript
基于jQuery制作小图标上下滑动特效
2017/01/18 Javascript
轻松实现jQuery添加删除按钮Click事件
2017/03/13 Javascript
使用VueCli3+TypeScript+Vuex一步步构建todoList的方法
2019/07/25 Javascript
Vue-cli 移动端布局和动画使用详解
2020/08/10 Javascript
[04:32]玩具屠夫中文语音节选
2020/08/23 DOTA
python提示No module named images的解决方法
2014/09/29 Python
python实现将pvr格式转换成pvr.ccz的方法
2015/04/28 Python
python安装模块如何通过setup.py安装(超简单)
2018/05/05 Python
python和pygame实现简单俄罗斯方块游戏
2021/02/19 Python
pytorch 求网络模型参数实例
2019/12/30 Python
pycharm中如何自定义设置通过“ctrl+滚轮”进行放大和缩小实现方法
2020/09/16 Python
Django创建一个后台的基本步骤记录
2020/10/02 Python
利用HTML5 Canvas制作一个简单的打飞机游戏
2015/05/11 HTML / CSS
TUMI澳大利亚网站:美国旅行箱包品牌
2017/03/27 全球购物
亚历山大·王官网:Alexander Wang
2017/06/23 全球购物
上海奥佳笔试题面试题
2016/11/16 面试题
教师节活动主持词
2014/04/02 职场文书
《小动物过冬》教学反思
2014/04/17 职场文书
情况说明书格式范文
2014/05/06 职场文书
运动会班级前导词
2015/07/20 职场文书
2016习总书记系列重要讲话心得体会
2016/01/15 职场文书
《小乌鸦爱妈妈》教学反思
2016/02/19 职场文书
JS精髓原型链继承及构造函数继承问题纠正
2022/06/16 Javascript