动态加载Go代码是可能的吗?

huangapple go评论82阅读模式
英文:

Is it possible to dynamically load Go code?

问题

如标题所述,我想根据仅在运行时可用的信息动态加载一个Go包(或不加载)。

目标是允许用户通过自定义包来扩展程序,以添加新的本地脚本命令。目前,每当我添加新的命令或想禁用某些命令时,我都需要编辑程序并重新编译,而如果我能够创建某种类似dll的东西,那么我就可以创建一个"import"脚本命令来搜索并加载一个命名的命令库。

对于好奇的人来说,我所说的程序是我用于各种事情的自定义命令脚本库。

我事先进行了一些搜索,结果看起来不太乐观,但我找不到明确的否定答案。

英文:

As the title says I want to dynamically load a Go package (or not) based on information only available at run time.

The objective is to allow the user to extend the program via custom packages that add new native script commands. Currently every time I add new commands or want to disallow some commands, I need to edit the program and recompile, whereas if I could make some kind of dll or the like then I could create a "import" script command to search for and load a named command library.

For the curious the program in question is custom command based scripting library that I use for all kinds of things.

I did some searching ahead of time, and the results don't look good, but I could not find a clear no.

答案1

得分: 14

Go目前还不支持动态库。Elias Naur最近发布了一些补丁,但尚未进行审核,而且不太可能包含在Go 1.2中。你可以在Google Groups上阅读相关讨论:

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

然而,还有另一种方法。你可以在单独的进程中启动插件,并使用net/rpc包与主应用程序进行通信。这样做还允许你动态启动/停止/重新编译单独的插件,并且它的优点是一个糟糕的插件不会导致程序崩溃。Go在网络通信方面表现出色,你只需要充分利用它。

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

你还可以考虑编写一个小脚本,用于监视当前目录的变化(使用fsnotify),并执行"go build"命令,然后重新启动程序。我在一些Web项目的本地开发中使用这种方法,效果很好。我几乎看不到任何编译时间,并且在切换和刷新浏览器窗口时速度非常快。与Go相比,我的Python开发周期(每次更改都需要重新启动解释器并重新导入所有模块,对于较大的项目可能需要很长时间!)感觉真的很笨拙。

英文:

Go does not support dynamic libraries yet. Elias Naur has recently published some patches, but they have not been reviewed yet and it is unlikely that they will be included in Go 1.2. You can read the discussions on Google Groups:

As far as I know, that are the most recent discussions about that topic.

There is however another approach. You can start your plugins in separate processes and use the net/rpc package to communicate with your main app. This also allows you to dynamically start / stop / recompile separate plugins and it has the advantage that a bad plugin can not crash your program. Go excels at network communication, you just have to make good use of it.

> I need to edit the program and recompile,

You can also consider writing a small script that watches for changes in the current directory (using fsnotify) and executes "go build" followed by a restart of your program. I use this approach on some of my web projects during local development and it works fine. I am not able to observe any compilation times and I am quite fast at switching and refreshing my browser window. My Python development cycle, where the interpreter has to be restarted and all modules have to be reimported on every change (and that might take a significant time in larger projects!), feels really clumsy in comparison to Go.

答案2

得分: 4

Go 1.8中支持这个功能。目前它还比较不成熟和基础,但终于有可能实现了。

此外,Mateusz Gajewski的go-bind-plugin项目可能会很有用,因为它简化了使用加载的插件。

根据plugin包的文档:

例如,一个定义如下的插件:

package main

// // 不需要C代码。
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())() // 输出 "Hello, number 7"
type Symbol interface{}
英文:

There's support for this in Go 1.8. It's pretty immature and rudimentary at the moment, but it's finally possible.

Also Mateusz Gajewski's go-bind-plugin project may be of interest, as it simplifies using loaded plugins.

From the plugin package documentation:

For example, a plugin defined as

package main

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

import "fmt"

var V int

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

may be loaded with the Open function and then the exported package symbols V and F can be accessed

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{}

答案3

得分: 0

好的,以下是翻译好的内容:

嗯,Go语言有一个dlopen包,所以至少你现在可以将共享库(DLL)加载到Go程序中了... 你可能需要使用C、C++或其他能够生成共享库的工具来编写你的扩展。

英文:

Well, there is a dlopen-package for Go -- so, at least, you can load your shared library (DLL) into your Go-program now... You'll, probably, have to code your extension in C, C++ or something else, for which you have tools capable of generating shared libraries.

huangapple
  • 本文由 发表于 2013年8月15日 01:00:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/18237863.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定