Go 语言是否能实现 Python 中 importlib 的功能 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
chaleaochexist

Go 语言是否能实现 Python 中 importlib 的功能

  •  
  •   chaleaochexist Apr 19, 2022 2822 views
    This topic created in 1469 days ago, the information mentioned may be changed or developed.
    python 的 apscheduler 中 可以将 job 保存在数据库中,原理很简单 用的`__import__`.将字符串转换成可执行函数了。

    但是 go 中没有啊。。。
    我想写一个带持久化的 go 版的 apscheduler 。 这块卡住了。。。
    16 replies    2022-04-20 10:27:44 +08:00
    iBugOne
        1
    iBugOne  
       Apr 19, 2022 via Android   4
    我怀疑楼主不懂编译语言和解释执行语言的区别
    westoy
        2
    westoy  
       Apr 19, 2022
    走 cgo 绕一遍 dlopen?
    seakingii
        3
    seakingii  
       Apr 19, 2022
    可以在你的程序里内置一个脚本引擎,比如 lua
    mengzhuo
        4
    mengzhuo  
       Apr 19, 2022
    呃……你需要的是恢复“执行栈”?还是仅仅是持久化执行的结果?
    不过 python 也不能恢复执行栈吧,所以我怀疑你只是想把当前的执行结果存档一下,可以用 gob (类似 pickle )

    倒是要我设计能 resume status 的话……Go 没办法强制指定 pc 和符号表,要恢复“执行栈”,需要在所有函数出入口记录好参数状态(“表”驱动),函数版本,执行环境变量,通过 offset 指定恢复,应该可以(发现了什么奇怪的用途)
    gabon
        5
    gabon  
       Apr 19, 2022 via iPhone
    内置一个编译器,然后启动个子进程。
    iyaozhen
        6
    iyaozhen  
       Apr 19, 2022
    @gabon 执行 go build 命令?
    GeruzoniAnsasu
        7
    GeruzoniAnsasu  
       Apr 20, 2022
    @mengzhuo 不可能的,还会有 goroutine 和 GC 的问题

    ----

    OP 换个思路:
    在静态语言中,所有函数都是「已持久化」的、嵌在程序中的。借助反射,函数的地址可以通过函数名查到,所以执行体存个名字就好了
    job 的另一个组成部分是参数,而保存参数还是比较简单的,毕竟有反射,如果你想,可以把 runtime 对象整个扫描一遍再用反射造回来
    Vegetable
        8
    Vegetable  
       Apr 20, 2022
    想实现动态脚本?

    用 build 代替你的__import__这种思路试试呗
    chaleaochexist
        9
    chaleaochexist  
    OP
       Apr 20, 2022
    @mengzhuo 都不是
    上下文不需要保存。

    我从 redis 里面把函数名和函数参数读取出来然后执行。 大概是这个意思。

    python 可以通过保存"module_name.func_name" 然后
    ```python
    func = __import__("module_name.func_name")
    func()
    ```
    这样执行。

    pickle 也可以,虽然我没试过 但是我觉得 gob 应该也可以。 但是把函数序列化,在反序列化, 应该没人这么干吧。


    目前的想法是在 main 启动的时候 配一个 map 将函数名和函数映射起来。 至于参数, 可以用我楼上说的反射实现。

    谢谢大佬。
    chaleaochexist
        10
    chaleaochexist  
    OP
       Apr 20, 2022
    @GeruzoniAnsasu #7 大佬说的反射是泛指还是特指 Go 的反射。 因为我没想明白 在 go 语言中如何通过函数名查找到函数的地址。 如果能实现的话, 那我的问题其实差不多就解决了。

    谢谢大佬。
    learningman
        11
    learningman  
       Apr 20, 2022
    go 的话,你已有的这个想法应该是唯一解了。。。顶多说写个 codegen 不用手动维护 map
    learningman
        12
    learningman  
       Apr 20, 2022
    可以 reflect.ValueOf(func).Call(params)这么整,但是还是要初始化
    275761919
        13
    275761919  
       Apr 20, 2022   2
    可以试试 yaegi ,github.com/traefik/yaegi ,感觉你说的是这个
    GeruzoniAnsasu
        14
    GeruzoniAnsasu  
       Apr 20, 2022   1
    @chaleaochexist

    我之前的想法是: 当你要定义一个新 Job 的时候: Schedule(Callback,time) Callback 必然已经是一个静态的函数了,而要持久化,callback 又不能是闭包。那么比如要求 Callback 写成固定名 struct 的 method ,类似这样:

    https://go.dev/play/p/cUw99-T55v8


    然后又想能不能根据类型信息反射出一个类实例,然后类实例包含一个重写掉的 Run method ,这样函数名就是固定的了,而且定义 Job 的方式能更灵活。 问题集中在怎么得到这个有类型的实例上


    然而研究了大概 6 个小时之后我发现
    1. reflect.Type 也是一个接口,意味着就算把类型信息 dump 出来了,我也没法轻易构造出一个实例化的 Type
    2. reflect.rtype 是 reflect.Type 接口最重要的实现,这个结构是有办法 dump 的( unsafe pointer 读),但不能存在覆写一个现存 reflect.rtype 的办法。 通过反射写这个结构会被 reflect.Value.SetXXX 的实现拒绝(有 flag 阻止写回去);而直接得到这个结构的 unsafepointer 尝试给它赋值会触发访问违例,原因不明。由于我也没用更 low level 的调试器去调( goland 而已),所以我也不知道是赋值语义还是类型转换语义的问题
    3. 不像 C/++ 有函数地址就可以强制转换出一个函数; golang 是无论如何都先得有 reflect.Type 的(光有地址没有用)。由于 2 ,reflect.Type 不能自由构造,因此在语言范围内能想到的 tricky way 都堵死了。




    有点蛋疼,前几天才有其他人说 golang 动态性差,确实是不得不承认的
    chaleaochexist
        15
    chaleaochexist  
    OP
       Apr 20, 2022
    @learningman #12
    reflect.ValueOf(func).Call(params)
    这个 func 我没有办法通过字符串拿到。 还是只能通过 map 找了。
    learningman
        16
    learningman  
       Apr 20, 2022   1
    @chaleaochexist 对,所以我说要初始化,但是应该可以用 codegen 来弄
    About     Help     Advertise     Blog     API     FAQ     Solana     956 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 46ms UTC 21:53 PVG 05:53 LAX 14:53 JFK 17:53
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86