V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
chaleaochexist
V2EX  ›  Go 编程语言

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

  •  
  •   chaleaochexist · 2022-04-19 20:55:45 +08:00 · 2304 次点击
    这是一个创建于 949 天前的主题,其中的信息可能已经有所发展或是发生改变。
    python 的 apscheduler 中 可以将 job 保存在数据库中,原理很简单 用的`__import__`.将字符串转换成可执行函数了。

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

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

    ----

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

    用 build 代替你的__import__这种思路试试呗
    chaleaochexist
        9
    chaleaochexist  
    OP
       2022-04-20 00:28:39 +08:00
    @mengzhuo 都不是
    上下文不需要保存。

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

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

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


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

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

    谢谢大佬。
    learningman
        11
    learningman  
       2022-04-20 00:54:42 +08:00
    go 的话,你已有的这个想法应该是唯一解了。。。顶多说写个 codegen 不用手动维护 map
    learningman
        12
    learningman  
       2022-04-20 00:55:59 +08:00
    可以 reflect.ValueOf(func).Call(params)这么整,但是还是要初始化
    275761919
        13
    275761919  
       2022-04-20 09:30:32 +08:00   ❤️ 2
    可以试试 yaegi ,github.com/traefik/yaegi ,感觉你说的是这个
    GeruzoniAnsasu
        14
    GeruzoniAnsasu  
       2022-04-20 09:53:55 +08:00   ❤️ 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
       2022-04-20 10:02:50 +08:00
    @learningman #12
    reflect.ValueOf(func).Call(params)
    这个 func 我没有办法通过字符串拿到。 还是只能通过 map 找了。
    learningman
        16
    learningman  
       2022-04-20 10:27:44 +08:00   ❤️ 1
    @chaleaochexist 对,所以我说要初始化,但是应该可以用 codegen 来弄
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2732 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 07:04 · PVG 15:04 · LAX 23:04 · JFK 02:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.