python热更新_reload 实现热更新

2023-11-15

什么是 reload

当我们在 python

的交互模式下测试某个类的时候,发现这个类的某个方法有错误进行了修改,而这个方法的输入又依赖于之前在交互模式下的好几个操作,这时要怎么办呢?如果重启交互模式,那么该方法依赖的操作就得重新再来一次,相当麻烦。这时

reload 就能派上用场了。 reload 内建方法用于重新导入一个模块,如果相应的python脚本代码被修改了,用 reload

重新导入后就是修改后的新模块而不需要重启整个程序了。

热更新

假设你有一个网站有不少的用户量,并时不时需要更新新功能。你不希望在更新新代码的时候把整个网站停掉重启进程,因为这期间可能会流失一部分用户,于是你就在想能不能只需要把旧代码替换成新代码无需重启进程就实现更新呢? reload 就可以实现这个功能。

待更新模块

在项目文件夹下我们创建个 long_op.py 文件,该文件代表了需要被更新的模块,其中的类 LongOp 模拟长时操作。

#coding:utf8

import time

import threading

class LongOp(threading.Thread):

def __init__(self, id):

super(LongOp, self).__init__()

self.id = id

def run(self):

for i in range(10):

print("New long op {} running.".format(self.id))

time.sleep(1)

print("New long op {} end.".format(self.id))

我们将 long_op.py 备份为 long_op.old.py , 并创建文件 long_op.new.py 作为修改后的新代码,用于在程序运行时替换 long_op.py 文件。 long_op.new.py 代码如下:

#coding:utf8

import time

import threading

class LongOp(threading.Thread):

def __init__(self, id):

super(LongOp, self).__init__()

self.id = id

def run(self):

for i in range(10):

print("New long op {} running.".format(self.id))

time.sleep(1)

print("New long op {} end.".format(self.id))

新旧代码只有输出有区别。

文件监控

当更新代码时我们需要知道文件发生了修改,才能在适当的时机动态加载修改后的新模块。 新建 file_monitor.py 文件并粘贴以下代码:

#coding:utf8

import os

import threading

import time

import sys

EXIT = False

class FileMonitor(threading.Thread):

def __init__(self, file2module=None, interval=3):

'''

:param files: files that need to be monitored

:param modules: objs that needs to be reloaded when corresponding files changes

:param interval:

'''

super(FileMonitor, self).__init__()

if not file2module:

file2module = {}

self._lock = threading.Lock()

self._file2module = file2module

self._interval = interval

self._modified_time = {} # file to last modified time to determine if reload is needed

for file in self._file2module:

self._modified_time[file] = self.get_modified_time(file)

@staticmethod

def get_modified_time(file):

state = os.stat(file)

return state.st_mtime

def run(self):

try:

global EXIT

EXIT = True

while EXIT:

with self._lock:

for file in self._file2module:

if self.get_modified_time(file) != self._modified_time[file]:

print("Reload module")

reload(self._file2module[file])

self._modified_time[file] = self.get_modified_time(file)

time.sleep(self._interval)

except KeyboardInterrupt as error:

print("KeyboardInterrupt caught")

sys.exit(0)

def add_file(self, file, module):

with self._lock:

self._file2module[file] = module

self._modified_time[file] = self.get_modified_time(file)

def stop_monitor(self):

global EXIT

EXIT = False

FileMonitor

实例会保存一份文件名映射到模块的字典_file2module,以及文件名映射到最后修改时间的字典_modified_time。 每隔

interval 秒检查一遍字典内的文件是否发生了修改,如果发生修改就重新载入对应模块。除了在初始化实例时传入 file2module

来指定需要监控的文件外还可以在实例化后通过方法 add_file 来增加需要监控的文件。 run 方法则为监督文件。

调度

新建文件 main.py, 复制粘贴以下代码:

#coding:utf8

import threading

import time

import random

from file_monitor import FileMonitor

import long_op # Can't do 'from long_op import LongOp' here, because reload only works on module level

fm = FileMonitor()

fm.add_file("long_op.py", long_op)

fm.start()

resource = threading.BoundedSemaphore(2)

threads = []

lock = threading.Lock()

EXITTHREADS = False

def start_thread():

while True:

resource.acquire()

print("Start new thread")

t = long_op.LongOp(random.randint(0,9))

with lock:

threads.append(t)

t.start()

if EXITTHREADS:

break

def clear_threads():

while True:

with lock:

for i, ele in enumerate(threads):

if not ele.isAlive():

threads.pop(i)

resource.release()

print("Release a thread")

time.sleep(3)

if EXITTHREADS:

break

t1 = threading.Thread(target=start_thread)

t2 = threading.Thread(target=clear_threads)

t1.start()

t2.start()

t1.join()

t2.join()

main.py 中实例化 FileMonitor, 添加待监控的文件 “long_op.py”

并在线程中运行监控逻辑,一旦被监控的文件发生了修改就会重新导入相应模块。接着使用了 BoundedSemaphore

和两个分别实现创建线程运行长时操作和清楚运行结束的长时操作的线程 start_thread 和

clear_threads,这两个线程会使得运行期间有两个 LongOp 长时操作线程不停输出,用以模拟业务逻辑。

运行 & 更新

启动程序

python main.py 将会启动程序,如下图将会看到有两个线程不断输出,其输出中带有 old 标识其为未更新的旧代码生成的实例。

替换程序

我们通过 cp long_op.new.py long_op.py 来覆盖旧代码。 当新代码被加载时会看到输出“Reload

module”。当重新加载模块后旧的 LongOp 实例还会继续运行,其还是旧的实例,而其实此时 long_op 模块已经被更新了,内部的

LongOp 类也是新的了,只是旧的实例还能运行直到它停止被销毁。在此之后再用 LongOp

类生成的实例就是新的实例了,在此两个旧实例被销毁的时间不同,还出现了旧实例和新实例并存的情况,即截图里 Old 和 New 间隔输出那段。

缺点 & 其它实现

因为 reload

方法只能重新载入整个模块,不能部分地载入模块内的内容,要支持这样的动态更新就需要使用模块化编程,即从需要更新的文件导入

只能整个模块的导入而不能只从中导入一个类或函数或变量。对应本文即不能 from long_op import LongOp 而只能 import long_op 并且之后都使用 long_op.LongOp 的方式使用 LongOp 类。

reload 会导致旧实例和新类,新对象同时存在的情况,如果这是在旧类里使用了 isinstance 或者 super

就会导致意想不到的错误和结果。因为预期 isinstance 和 super

参数为当前实例对应的类,即旧类,但此时旧类已经不存在,被新类覆盖了。

还有其它方法实现动态更新,即直接读取脚本内容,使用 eval 来执行代码。在 github 上看到个如此实现的项目 reloadr, 具体还没细看。 对于本文的示范,有什么改进的也欢迎推送到我的 github repo。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python热更新_reload 实现热更新 的相关文章

  • MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]

    MarshalAs 指示如何在托管代码和非托管代码之间封送数据 简单点说 托管代码是一Microsoft的中间语言 它主要的作用是在 NET Farmework的CLR执行代码前去编译源代码 也就是说托管代码充当着翻译的作用 源代码在运行时
  • 初识网络原理

    目录 局域网 简称LAN 广域网 IP地址 端口号 协议 协议分层 互联网的分层 网络设备的分层 封装和分用 局域网 简称LAN 简单来说就是把两台或多台机器连接在一起 局部组建的一种私有网络 局域网内的主机之间能方便的进行网络通信 而局域
  • Mysql 数据库创建用户,管理用户权限

    一 创建用户 为什么要创建不同的用户呢 因为root用户权限太大 为了安全起见 创建不同的用户 并赋予不同的权限 可以有效保证数据库的安全 1 使用 root 用户登录 Mysql mysql u root p 注意 若 mysql u r
  • 两波形相位差的计算值_连续模式PFC功率MOSFET电流有效值、平均值计算

    中大功率的ACDC电源都会采用有源功率因数校正PFC电路来提高其功率因数 减少对电网的干扰 在PFC电路中 常用的结构是BOOST电路 功率MOSFET工作在开关状态 将输入的电流斩波为和输入正弦波电压同相位的 具有正弦波包络线的开关电流波
  • linux日志清理脚本

    日常日志清理脚本 1 压缩文件 SUFFIX date d yesterday Y m d CURRENT date s echo CURRENT 压缩 FILES data logs shop nohup for file in FILE
  • 技术宅学会几招FFmpeg

    有些时候 我需要对某个视频文件做一些简单的处理 也或者是受亲戚朋友的委托吧 又不好意思推辞 因为人家觉得你是搞技术的 这点小事应该能轻松搞定 但是 我犯不着为这点事去安装一个笨重的多媒体软件 我也不想去网上随便找个免费的小工具 怕它不干净
  • C++ 惯用法之 PIMPL

    背景 PIMPL 是 C 中的一个编程技巧 意思为指向实现的指针 具体操作是把类的实现细节放到一个单独的类中 并用一个指针进行访问 二进制兼容性 概述 二进制兼容是指当库文件升级后所有使用该库的应用程序不必重新编译 其本质就是类的内存布局不
  • 闭环系统的零极点图判定稳定性_负反馈系统

    负反馈的作用机理是 当受外在激励或外界干扰时 系统将通过负反馈抑制或者减弱这种外在激励或者干扰 而使系统达到一个新的平衡状态 负反馈系统在工作过程是一个闭环系统 而分析开环特性只是辅助理解 因为闭环系统不容易模拟 模型不直观 在图1 1 a
  • 测试总结报告写法简单总结

    1 编写目的 编写目的先总的说本文档是什么文档 编写此文档的目的是什么 总的说一下 然后在写以下具体的编写目的 最后的预期读者从需求里粘过来 2 项目背景 从方案中粘项目背景 完全粘过来 不用任何改动 3 测试参考文档 参考文档写任务书和需
  • window重启Nginx的BAT脚本

    1 脚本入参 SET NGINX DIR C Zone nginx 1 21 4 nginx 1 21 4 该路径配置成nginx的根目录文件夹 2 Nginx管理脚本 echo off chcp 65001 color 0a rem 当前
  • C#上位机软件支持中英文多语言切换MultiLanguage

    最近遇到一个项目 客户是国外的 开发上位机程序是在中国 需支持中英文多语言切换 多语言切换思路 使用不同的xml配置文件来映射不同的语言 窗体加载时从默认语言DefaultLanguage xml中读取配置 比如中文语言 对应Chinese
  • 大数据上机基础—HDFS文件操作

    本文为在校学习大数据课程期间 对厦门大学林子雨老师大数据技术原理与应用 第三章 分布式文件系统HDFS学习指南一文进行的整理 方便自己学习查看 原文地址为大数据技术原理与应用 第三章 分布式文件系统HDFS学习指南 操作系统为Ubuntu1
  • Ubuntu下Anaconda安装opencv

    作者 黄钟健 注意 文中 xxx 表示自定义的名称 需要自己根据实际情况替换 一 安装opencv依赖库 在终端上敲入以下命令 sudo apt get install build essential sudo apt get instal
  • react多层循环跳出最外层

    function test let baseCount 5 baseWhile while baseCount let count 10 while count if count 5 break baseWhile console log
  • mac homebrew fatal: not in a git directory

    问题 在用homebrew安装软件时 提示报错 fatal not in a git directory 解决办法 先执行 brew v 出现如下提示 Homebrew 4 0 1 60 g6ad9294 fatal detected du
  • Keras自定义损失函数的4个方法

    百度能够找出来的最原始的资源貌似是这个链接 里面提供了三种方法 但是都不能解决目前我的问题 获取是我没看懂吧 主要我的custom损失函数的参数不是简单的y true y pred 又是从中间层计算loss https spaces ac
  • 驱动篇 -- PMOS管应用

    感谢阅读本文 在接下来很长的一段时间里 我将陆续分享项目实战经验 从电源 单片机 晶体管 驱动电路 显示电路 有线通讯 无线通信 传感器 原理图设计 PCB设计 软件设计 上位机等 给新手综合学习的平台 给老司机交流的平台 所有文章来源于项
  • javaIO流05:FileReader和Filewriter

    FileReader FileReader是字符流 按照字符来操作io FileReader的关系继承图 2 FileReader 相关方法 new FileReader File String read 每次读取单个字符 然后返回该字符
  • 卷积的本质及物理意义(全面理解卷积)

    卷积的本质及物理意义 提示 对卷积的理解分为三部分讲解1 信号的角度2 数学家的理解 外行 3 与多项式的关系 1 来源 卷积其实就是为冲击函数诞生的 冲击函数 是狄拉克为了解决一些瞬间作用的物理现象而提出的符号 古人曰 说一堆大道理不如举

随机推荐

  • ChatGPT指令大全(英文版)

    ChatGPT指令大全 英文版 前言 Act as a Linux Terminal Act as an English Translator and Improver Act as position Interviewer Act as
  • WebApi 登录身份验证

    前言 Web 用户的身份验证 及页面操作权限验证是B S系统的基础功能 一个功能复杂的业务应用系统 通过角色授权来控制用户访问 本文通过Form认证 Mvc的Controller基类及Action的权限验证来实现Web系统登录 Mvc前端权
  • 将代码提交到Github代码托管平台

    本篇文章呢 阿Q将为大家讲解如何将自己的代码上传到github这个第三方代码托管平台 并更新代码 阿Q本次就以上一个Dialog的Demo为例 将其上传到github 要想上传代码到github 大家需要做一下准备工作 首先要将Git GU
  • Softmax的实现

    详解 https zhuanlan zhihu com p 25723112
  • 带icon的输入框el-input 给icon图标绑定点击事件

    element官网传送门 带icon的输入框有两种方式 选择第二种 添加点击事件
  • opengl API glCheckFramebufferStatus详解

    Name glCheckFramebufferStatus glCheckNamedFramebufferStatus check the completeness status of a framebuffer C Specificati
  • SQL解析Json字段

    MySQL支持原生JSON类型 使用JSON数据类型相较于将JSON格式的字符串存储在String型中的优势有 存储时会自动验证JSON文本 可以优化存储格式 存储在JSON型中的JSON文本会被转换成一个支持快速读取的文档元素 这样在使用
  • python基础一:计算机要点学习

    一 计算机的基本概念 1 计算机是什么 计算机是一种用于高速运算的电子机器 手机 电脑 计算器等 特点 数值计算 逻辑计算 对事物进行逻辑分析并进行判断得到的计算结果 存储记忆功能 计算机是能够按照程序运行 自动 高速处理数据的现代化电子设
  • postman几种常见的请求方式

    1 get请求直接拼URL形式 对于http接口 有get和post两种请求方式 当接口说明中未明确post中入参必须是json串时 均可用url方式请求 参数既可以写到URL中 也可写到参数列表中 都一样 请求时候都是拼URL 2 pos
  • [深入理解Android卷二 全文-第六章]深入理解ActivityManagerService

    由于 深入理解Android 卷一 和 深入理解Android卷二 不再出版 而知识的传播不应该因为纸质媒介的问题而中断 所以我将在CSDN博客中全文转发这两本书的全部内容 第6章 深入理解ActivityManagerService 本章
  • 魏副业而战:付费是最快的成长途径

    我是魏哥 与其在家躺平 不如魏副业而战 在生活中 为了提高孩子学习成绩 你会给他报辅导班 在工作中 为了提升工作效率 为了晋升 你会报课 考证书 但很少人为了自己的成长而主动付费学习 这是为什么呢 因为他没认识到付费的价值 魏哥之前也是喜欢
  • 互联网+商业模式

    大数据商业模式 10种商业模式 一 人工智能 数据 物体 智能 人工智能是数据变现的最好方式 但是目前是2B的智能买单意愿更强 GDP 20 数据是为人服务的 人接触最多的是物体 数据的智慧将延伸人的五官 拓展人的四肢 这些都依赖硬件 数据
  • 【数据结构与算法】链表OJ练习题

    作者 一只大喵咪1201 专栏 数据结构与算法 格言 你只管努力 剩下的交给时间 习题 1 移除链表元素 2 反转链表 3 链表的中间结点 4 链表中倒数第k个结点 5 合并两个有序链表 6 链表分割 7 链表的回文结构 8 相交链表 9
  • Java:求一个数组中连续子元素最大和

    public class TestArray public static int FindGreatestSumOfSubArray int array if array length 0 array null return 0 int c
  • log4j:WARN No appenders could be found for logger 解决办法

    使用log4j时不起作用 每次执行完出现以下提示 log4j WARN No appenders could be found for logger org apache ibatis logging LogFactory log4j WA
  • Linux性能分析之perf(1)基础知识总结

    Linux 09 之perf 1 基础知识总结 Author Onceday Date 2023年1月31日 漫漫长路 才刚刚开始 参考文档 Tutorial Perf Wiki kernel org linux性能分析工具专题 perf
  • FPGA-VGA协议实践

    前言 概述 VGA Video Graphics Array 视频图形阵列 是一种视频传输标准 具有分辨率高 显示速度快 颜色丰富等优点 不支持音频传输 硬件设备 FPGA开发板DE2 115 软件环境 软件环境 Quartus 一 VGA
  • one-hot Embedding 理论知识详解 + 代码实操 (为学习笔记模式,同时附完整代码)【独热向量编码】

    目 标 使用one hot Embedding 处理数据库查询语句 使其变成向量模式 以下为个人学习笔记和学习过程中用到的完整代码 环 境 腾讯云服务器 Linux系统 具体环境会在代码段前进行标注 目录 一 one hot 理论基础 二
  • pytest-mock的使用

    mock介绍 当一个功能依赖另一个功能时 而这个功能还没有完善 需要使用mock来模拟依赖的返回 mock主要有以下几个库 unittest mock python内置的用于mock的库 有Mock MagicMock path等类可以使用
  • python热更新_reload 实现热更新

    什么是 reload 当我们在 python 的交互模式下测试某个类的时候 发现这个类的某个方法有错误进行了修改 而这个方法的输入又依赖于之前在交互模式下的好几个操作 这时要怎么办呢 如果重启交互模式 那么该方法依赖的操作就得重新再来一次