hotfix原理
在Python热更新详解一文中,我们介绍了reload的方式来进行热更新,但是reload方式不管怎么优化,总是会卡那么一下子,对于频繁需要热更新且延迟要求低的系统来说是不能接受的。于是就有了hotfix技术,hotfix技术的本质是把更新的代码或者配置数据在编译后,直接顶替老的函数。这样就能在运行时热更新。
hotfix实例
下面代码是hotfix的demo,先原始代码跑一遍输出。在Hotfix.do_hotfix()
中进行热更新,然后再次运行输出。
# TestModule
a = 1
class A(object):
def class_func(self):
print 'object A'
def module_func():
print 'module_func'
print a
# HotfixDemo
import TestModule
import Hotfix
if __name__ == '__main__':
TestModule.module_func()
obj = TestModule.A()
obj.class_func()
while 1:
a = raw_input()
Hotfix.do_hotfix()
TestModule.module_func()
obj.class_func()
当我们需要进行hotfix热更新时,执行do_hotfix
函数即可,do_hotfix
读取HotfixCode.py
的代码并编译。HotfixCode.py
里对需要热更新的函数加上replace_func
装饰器。
# Hotfix.py
def replace_func(obj, name=None):
def func(f, name=name):
if name is None:
name = f.func_name
setattr(obj, name, f)
print 'replace func %s done' % name
return f
return func
def do_hotfix():
hotfix_code_str = open('./HotfixCode.py').read()
hotfix_code = compile(hotfix_code_str, 'HotfixCode', 'exec')
env = {}
exec hotfix_code in env
print 'hotfix done'
print
# HotfixCode.py
import Hotfix
def zhangsan():
import TestModule
TestModule.a = 100
@Hotfix.replace_func(TestModule)
def module_func():
print 'hotfix ..... module_func'
print TestModule.a
@Hotfix.replace_func(TestModule.A)
def class_func1(self):
pass
@Hotfix.replace_func(TestModule.A)
def class_func(self):
self.class_func1()
print 'hotfix ..... object A'
def lisi():
pass
def run_all():
zhangsan()
lisi()
run_all()
运行结果:
module_func
1
object A
replace func module_func done
replace func class_func1 done
replace func class_func done
hotfix done
hotfix ..... module_func
100
hotfix ..... object A
总结
通过hotfix过程可以看出这种热更新方式实现简单,且运行效率极高,远不是reload能比。缺点是需要重新额外维护一份hotfix_code,这一步比较耗时。所以hotfix热更新只适合线上运行的系统或者客户端。如果是在研发阶段,建议直接使用reload。
另外需要注意的是@Hotfix.replace_func
对设置的回调函数不生效,如果想要生效的话可以对老的函数进行改造,把老的function的func_code、func_doc、func_dict、func_defaults引用新function的属性。