动态载入, import 之类的有什么轮子吗?

2023-03-11 16:56:21 +08:00
 LeeReamond

需要实现的效果,比如一个服务在跑,然后服务依赖 n 个插件,插件放在单独一个文件夹里,每一个文件对应一个插件,插件随时可以变化,主体服务希望能不重启直接动态载入新代码这样

印象里多年前研究过这个功能,是可以实现的,但是好像有些麻烦。有什么现成的轮子吗?

1763 次点击
所在节点    Python
11 条回复
noqwerty
2023-03-11 17:04:39 +08:00
可以直接用 importlib 实现: https://docs.python.org/3/library/importlib.html
learningman
2023-03-11 21:10:10 +08:00
加载用 importlib 是可以搞的,但是清除旧的非常麻烦
ClericPy
2023-03-11 21:10:25 +08:00
我刚做了一个类似的...

假装是个动态脚本的 RPC, 通过 URL route 选择模块路径, 比如类似格式和很多常见模块的 entrypoint 一样, package.module:function 的方式, 传参兼容 params 和 Post form 以及 post JSON 多种方式, 目前参数只支持 kwargs 直接塞函数 **kwargs 里, 之后会根据 inspect 提取函数参数列表来做 validate 相关以及自动生成表单

然后动态载入刷新代码什么的, 我是每隔一段时间或者用 watchfile 的方式查看文件变化就从 sys.modules 里删掉, 下次导入就是新的代码了, 以前想过太多 reload 的用法, 发现最简单的就是直接删掉旧的...

这套东西还没时间开源, 难度不大自己琢磨琢磨也就明白了
LeeReamond
2023-03-11 21:44:32 +08:00
@ClericPy 你的意思是用 insepect 监控代码有没有变化,有就删掉旧的,然后每个插件用某种特定方式命名这种感觉?
ClericPy
2023-03-11 22:01:25 +08:00
@LeeReamond

什么啊... inspect 查看函数入参类型的, pydantic 做校验, 类型错误就不执行了

监控变化用 watchdog 看文件变化, 删掉的逻辑是你只要导入过的模块一般 sys.modules 里面 del 掉, 再导入一次就是新代码了, 不用特定命名, 只要 import path 固定一个目录, 会自动去搜模块名字的. 我那个格式是 URL 路径的格式, 不是命名格式

如果不放心害怕有篡改文件或者有人偷偷注入什么东西, 我之前还想了做对整个 .py 文件加盐哈希然后哈希值放到文件第一行, 到时候导入前先判断文件对不对
lolizeppelin
2023-03-12 11:50:58 +08:00
有, openstack 出品 stevedore

但必须按标准写 python setup.py,生成 egg 文件

总之就是符合 pkg_resources 那套标准
lolizeppelin
2023-03-12 11:51:42 +08:00
哦 看错了不好意思...
featureoverload
2023-03-13 14:21:56 +08:00
不是有特殊需求的软件,就实现 os.fork+importlib.import_module 好了。这种应该是最简单的
featureoverload
2023-03-13 14:24:55 +08:00
@featureoverload 这种应该是最简单的机制了。

有内存数据(变量 /对象 /数据结构)交换的话,就使用 multiprocessing+importlib.import_module 可以解决。
LeeReamond
2023-03-13 17:32:38 +08:00
@featureoverload fork 在这里是干什么用的呢
featureoverload
2023-03-14 09:51:51 +08:00
@LeeReamond 原本的程序(父进程)负责主 /核心逻辑,比如判断动态导入等。

在需要动态导入的时候,以及动态导入之后(使用导入的模块)做的事情,在 fork 出来的程序处理。

这样 [动态导入做的事情] 完成之后,fork 出来的程序(子进程)就让它自己结束--进程销毁;

------

这样就是“业务逻辑”和“核心逻辑”分离,包括进程内的一切变量等等。

核心逻辑控制什么时候动态导入,业务逻辑实际执行导入和业务行为。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/923178

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX