是否可以动态加载Go代码?

时间:2013-08-14 17:00:33

标签: go

正如标题所说,我想根据仅在运行时提供的信息动态加载Go包(或不)。

目标是允许用户通过添加新的本机脚本命令的自定义包扩展程序。目前每次添加新命令或想要禁用某些命令时,我都需要编辑程序并重新编译,而如果我可以制作某种dll之类的话,那么我可以创建一个“import”脚本命令来搜索和加载一个命名的命令库。

好奇的是,有问题的程序是我用于各种事情的基于自定义命令的脚本库。

我提前做了一些搜索,结果看起来不太好,但我找不到明确的否。

3 个答案:

答案 0 :(得分:15)

Go还不支持动态库。 Elias Naur最近发布了一些补丁,但它们还没有被审查过,它们不太可能被包含在Go 1.2中。您可以阅读有关Google网上论坛的讨论:

据我所知,这是有关该主题的最新讨论。

然而,还有另一种方法。您可以在单独的进程中启动插件,并使用net/rpc包与主应用程序进行通信。这也允许您动态启动/停止/重新编译单独的插件,它的优点是坏插件不会崩溃您的程序。擅长网络通信,你只需要好好利用它。

  

我需要编辑程序并重新编译,

您还可以考虑编写一个小脚本来监视当前目录中的更改(使用fsnotify)并执行“go build”,然后重新启动程序。我在本地开发期间对我的一些Web项目使用这种方法,它工作正常。我无法观察任何编译时间,我在切换和刷新浏览器窗口时非常快。我的Python开发周期,必须重新启动解释器,并且必须在每次更改时重新导入所有模块(这可能需要在较大的项目中花费大量时间!),与Go相比,感觉非常笨拙。

答案 1 :(得分:3)

Go 1.8支持此功能。目前它还很不成熟和初级,但它终于可能了。

Mateusz Gajewski的go-bind-plugin项目也可能会引起人们的兴趣,因为它简化了使用加载的插件。

来自plugin package文档:

例如,一个定义为

的插件
package main

// // No C code needed.
import "C"

import "fmt"

var V int

func F() { fmt.Printf("Hello, number %d\n", V) }

可以加载Open函数,然后可以访问导出的包符号V和F

p, err := plugin.Open("plugin_name.so")
if err != nil {
    panic(err)
}
v, err := p.Lookup("V")
if err != nil {
    panic(err)
}
f, err := p.Lookup("F")
if err != nil {
    panic(err)
}
*v.(*int) = 7
f.(func())() // prints "Hello, number 7"
type Symbol interface{}

答案 2 :(得分:0)

好吧,有一个dlopen-package for Go - 所以,至少,您现在可以将您的共享库(DLL)加载到您的Go程序中......您可能需要编写您的扩展程序代码C,C ++或其他东西,你有能够生成共享库的工具。