介绍:

热更新,就是在维持服务不间断的情况下,对软件代码逻辑或配置数据进行更新修复。随着游戏项目引入了脚本语言以后,热更新技术逐渐成为了标配,在我经历过的游戏项目中,无论是服务端还是客户端,版本的更新迭代都是围绕着静态patch和动态patch(热更新)来进行的。下面来谈一下客户端python热更新的处理。

原理:

1. 标准import

我们知道,import可以导入一个标准的python模块,将模块载入内存,并加到sys.modules中。多次import同一模块只是将名称导入到当前的Local名字空间,也就是一个模块不会重复载入。

2. reload函数

reload()函数可以重新载入已经导入的模块,这样看起来就可以热更新python模块了。可惜的是,python原生的reload函数远不能满足游戏热更新的问题,原因如下:

  • reload重新加载的模块不会删除旧版本的模块,也就是已经引用的旧模块无法更新
  • 同样因为不能旧对象的引用,使用from ... import ... 方式引用的模块同样不能更新
  • reloas(m)后,class及其派生class的实例对象,仍然使用旧的class定义。
  • 加载模块失败时候,没有rollback机制,需要重新import该模块

因此,有必要结合游戏的情景,自定义适合的reload。新的自定义reload目的是为了达到在原程序不结束的情况下,让程序能动态加载改动后的代码。主要想达到下面两点:

  • 提升开发期的开发效率
  • 在游戏不重启的情况下修复紧急BUG

实现:

热更新当中实际的重点在于如何让已经创建的对象获得新代码的变化,以及在reload前后不产生类型上的不一致。刷新function,class内定义的method比较容易实现,但对于刷新module内定义的变量,class内定义的变量,还有新增加的成员变量,则需要有统一的约定。所以,在热更新过程中,我们只要考虑好代码更新和数据更新这两点,那么更新就是可行的。

下面罗列一下新的reload具备哪些特性:

①更新代码定义(function/method/static_method/class_method)

②不更新数据(除了代码定义外的类型都当作是数据)

③在module中约定reload_module接口,class中约定reload_class接口,在这两个接口中手动处理数据的更新,还有更多的约定和接口待完成

替换函数对象的内容

# 用新的函数对象内容更新旧的函数对象中的内容,保持函数对象本身地址不变
def update_function(oldobj, newobj, depth=0):setattr(oldobj, "func_code", newobj.func_code)setattr(oldobj, "func_defaults", newobj.func_defaults)setattr(oldobj, "func_doc", newobj.func_doc)

替换类的内容

# 用新类内容更新旧类内容,保持旧类本身地址不变
def _update_new_style_class(oldobj, newobj, depth):handlers = get_valid_handlers()for k, v in newobj.__dict__.iteritems():# 如果新的key不在旧的class中,添加之if k not in oldobj.__dict__:setattr(oldobj, k, v)_log("[A] %s : %s"%(k, _S(v)), depth)continueoldv = oldobj.__dict__[k]# 如果key对象类型在新旧class间不同,那留用旧class的对象if type(oldv) != type(v):_log("[RD] %s : %s"%(k, _S(oldv)), depth)continue# 更新当前支持更新的对象v_type = type(v)handler = handlers.get(v_type)if handler:_log("[U] %s : %s"%(k, _S(v)), depth)handler(oldv, v, depth + 1)# 由于是直接改oldv的内容,所以不用再setattr了。else:_log("[RC] %s : %s : %s"%(k, type(oldv), _S(oldv)), depth)# 调用约定的reload_class接口,处理类变量的替换逻辑object_list = gc.get_referrers(oldobj)for obj in object_list:# 只有类型相同的才是类的实例对象if obj.__class__.__name__ != oldobj.__name__:continueif hasattr(obj, "x_reload_class"):obj.x_reload_class()

staticmethod

def _update_staticmethod(oldobj, newobj, depth):# 一个staticmethod对象,它的 sm.__get__(object)便是那个function对象oldfunc = oldobj.__get__(object)newfunc = newobj.__get__(object)update_function(oldfunc, newfunc, depth)

classmethod

def _update_classmethod(oldobj, newobj, depth):oldfunc = oldobj.__get__(object).im_funcnewfunc = newobj.__get__(object).im_funcupdate_function(oldfunc, newfunc, depth)

模块的更新也是相类似,就不一一粘贴了,只是在原来的reload基础上进行改良,对于模块热更新,还约定了一个reload_module接口,可以自定义数据的更新。

下面添加一些用例:

def x_reload_class(self):""" 热更新后,每个重新对象的实例都会执行这个函数由于新老对象的替换不会重新调用构造函数,因此有必要对热更新的类对象执行初始化逻辑处理新老变量的修复,函数执行环境的修复"""self._new_var = 5000    # 新变量的初始化self.init_widget()      # 新修复的逻辑

目前的热更新模块已经在开发调试中使用,可以方便地完成一些更新任务,但是要更新到远程客户端,还需要更多的规范和接口来处理,如闭包,内部局部变量等,需要逐步地学习和完善。

客户端python热更新相关推荐

  1. python flask热更新_客户端python热更新

    介绍: 热更新,就是在维持服务不间断的情况下,对软件代码逻辑或配置数据进行更新修复.随着游戏项目引入了脚本语言以后,热更新技术逐渐成为了标配,在我经历过的游戏项目中,无论是服务端还是客户端,版本的更新 ...

  2. unity python热更新_Unity热更新介绍和测试方法

    最近项目中增加了热更新了功能,程序也完成了相应的开发,接下来就需要对这个模块进行相应的测试工作了,在测试开始之前,了解下其原理总是很有好处的. 1:什么是热更新 简单的理解就是:用户重启客户端就能实现 ...

  3. python热更新原理_Python功能点实现:数据热更新

    关键词:热更新 | 热重载 | 定时更新 | 即时更新 | 缓存 | functools | cachetools | LRU | TTL 假设应用需要加载一个配置文件config.txt,一般的做法 ...

  4. Python在游戏中的热更新

    介绍: 热更新,就是在服务器不重启的的情况下,对游戏增加新的功能或者修复出现bug 的代码.游戏更新迭代速度快,催生了热更技术的需求,在我经历过的游戏项目中,无论是服务端还是客户端,版本的更新都是围绕 ...

  5. UE4 热更新系统开发

    哈喽,大家好,我叫人宅,很高兴和大家分享本套课程的内容. 在我们部署好我们的服务器后,有没有为我们的资源更新和资源下载而苦恼过,有没有为UE4 pak加载加密和读取解密而费尽脑汁过,有没有为我们资源压 ...

  6. 移动端热更新方案(iOS+Android)

    PPT资源包含iOS+Android 各种方案分析:https://github.com/qiyer/Share/blob/master/%E7%83%AD%E6%9B%B4%E6%96%B0%E5% ...

  7. webpack热更新原理-连阿珍都看懂了

    前言 在旧开发的时代,前端项目在开发的过程中修改代码,很有可能是手动切到浏览器刷新页面来看到改动效果.操作不方便且页面之前的编辑记录也都丢失,体验可以说为0.想象一下一个表达你努力填满了所有输入项,结 ...

  8. vite1.x 热更新(HMR)的实现原理

    前言 将近一年前自己尝试阅读vite源码(2.x),虽然也有些收获但整体并没有到达我的预期,对于vite也是停留在一知半解的程度上.最近想重新开始学习vite,但回顾之前的学习历程,感觉不太想继续之前 ...

  9. python程序更新实现_Python 软件热更新

    Python 软件热更新 本篇文章涉及技术知识如下: Redis threading 多线程 PyQt5 importlib 热更新 场景 咱们在平时运行一些长时间都会一直运行的软件(如:某些云同步软 ...

最新文章

  1. 龙芯架构应用迁移技术分享——搜狗输入法应用迁移
  2. Verilog初级教程(9)Verilog的运算符
  3. Linux centos 集群下ssh无密码
  4. 处理Xcode8输出无用的Log信息
  5. 第三次学JAVA再学不好就吃翔(part117)--单例设计模式
  6. canoco5冗余分析步骤_打造高性能的大数据分析平台
  7. 一个 redis 异常访问引发 oom 的案例分析
  8. Java(TM) platform SE binary 占用cpu过高
  9. 【软件测试】软件测试的基本流程(一般步骤)
  10. 【数据结构的魅力】005.链表问题专项
  11. caffe---之eltwise层
  12. 问题六十八:着色模型(shading model)(2)——光照模型(Light model)
  13. 2022年五一数学建模竞赛C题
  14. python进程池Pool的apply与apply_async到底怎么用?
  15. 年底了,你总结了吗?我先来。
  16. 看董事长陈睿11周年演讲,一起了解B站未来的三个使命吧
  17. 水波纹+仿探探卡片滑动+飘赞动画
  18. pytorch tensor 初始化_Pytorch - nn.init 参数初始化方法
  19. 量子力学科普书籍《见微知著》为什么值得读,看看目录就懂了
  20. android 点击震动,Android应用中实现点击按钮震动

热门文章

  1. 2021人大附中高考成绩查询,2021年人大附中录取分数线预测
  2. jvm 垃圾回收(常见算法介绍)
  3. 计算机游戏性能测评,总结:游戏性能属均衡_联想 IdeaCentre B325-劲速型_一体电脑评测-中关村在线...
  4. 怎么用百度之百度语法,通过一定的语法搜索可以准确的搜索到关键东西。
  5. 金仓数据库KingbaseES客户端编程开发框架-Django(2. 概述)
  6. 测试做得好,犯错少不了【30个最容易犯的错误】谨记
  7. 首届未来科学大奖得主薛其坤:神奇的量子世界
  8. Caused by: android.content.res.Resources$NotFoundException: File res/drawable/main_tab_conversation_
  9. 1331. 数组序号转换 : 简单模拟题
  10. Xamarin 跨平台应用开发(3)——数据与项目结构