Go 插件系统,一个凉了快半截的特性?
创始人
2025-05-03 18:21:51
0

[[417690]]

本文转载自微信公众号「脑子进煎鱼了」,作者陈煎鱼。转载本文请联系脑子进煎鱼了公众号。

大家好,我是煎鱼。

在 Go 语言中,有一个好像很好用,但却比较少人提及的功能,那就是 Go Plugin。

目前在 Go 工程中普遍还没广泛的使用起来,覆盖率不高。在 Go issues 上吐槽挺多,甚至感觉有点像凉了半截的样子。

前段时间小咸鱼的同事问了他这功能怎么用,他正想甩出一个链接,但发现...煎鱼竟然没写过,这不,Go 知识板块的文章地图得补全。

今天煎鱼就大家一起学习 Go Plugin,看看为什么会说感觉 “有点像凉了半截” 的样子,打开来看看这个问题在哪。

是什么

Go Team 最早在 Go1.7 实验,在 Go1.8 正式引入了 Go Plugin 的机制。于 2016 年发布,一开始仅支持 Linux 实现:

Go Plugin 机制实现了 Go 插件的加载和符号解析,能够支持将我们所编写的 Go 包编译为共享库(.so)。

这样 Go 工程就可以加载所编译好的 Go Plugin(已经变成了共享库文件),在程序中调用共享库中的函数、常量、变量等使用。也称其为 Go 语言中的热插拔的插件系统。

截止 Go1.17 为止,Go Plugin 仅支持在 Linux、FreeBSD 和 MacOS 上运行,还不支持 Windows。

为什么需要

Go 语言是静态语言,正常我们写一个程序,分如下两个角度来看:

  • 从代码编写的角度来看:我们在程序编写的时候就已经把所有的功能实现给确定了,不会发生什么根本性的变化。
  • 从程序的角度来看:在 Go 进行编译时,就已经把所有引用的标准库、第三方库等都编译打包好进二进制文件了,因此也就无法在运行时去动态加载,所以没法有其它的可能性。

那么为什么需要 Go Plugin 呢,原因如下:

  • 可插拔的插件:程序能够随时的安装插件,也能够卸载他,获得更多运行时的自定义能力。
  • 可动态加载运行时模块:随时安装了插件,自然也就需要可自行决定运行哪个插件的模块了。
  • 可独立开发插件、模块:主系统和子插件,可能由不同的团队开发和提供,也更有价值。

其实本质上还是希望程序能够在运行时实现动态的外部加载,根据不同的条件、场景加载不同的插件功能。

使用方法

通用概念

Go 官方给出的例子非常简单,只需要在 Go 编译时指定为插件就可以了。

编译的命令例子如下:

  1. go build -buildmode=plugin 

当一个插件初次被打开时,所有尚未成为程序一部分的包的init函数被调用。不过主函数不被运行。需要注意一个插件只会被初始化一次,插件不能被关闭。

其共有如下几个 API:

  1. type Plugin 
  2.     func Open(path string) (*Plugin, error) 
  3.     func (p *Plugin) Lookup(symName string) (Symbol, error) 
  4. type Symbol 
  • Plugin.Open:开启一个 Go 插件。如果一个路径已经被打开,那么将返回现有的 *Plugin。
  • Plugin.Lookup:在插件中搜索名所传入的符号,符号是任何导出的变量或函数。如果没有找到该符号,它会报告一个错误。

主要就是细分为插件和符号,符号(Symbol)本身是一个 interface,在调用 Plugin 相关方法后还是需要进一步断言才能使用。

实际编写

了解基本定义后,我们定义一个插件,一般我们会有个 plugins/ 的目录,作为主程序的附属插件集。

插件的代码如下:

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. var V int 
  6.  
  7. func F() { 
  8.  fmt.Printf("脑子进了 %d 次煎鱼 \n", V) 

包名必须为 main,在该插件根目录运行:

  1. go build -buildmode=plugin -o plugin.so main.go 

就可以看到在编译的目录下多出了 plugin.so 文件,这就是这个插件经过编译后的动态库 .so 文件。

随后只需在主程序加载这个插件就可以了,如下:

  1. import ( 
  2.  "plugin" 
  3.  
  4. func main() { 
  5.  p, err := plugin.Open("plugin.so") 
  6.  if err != nil { 
  7.   panic(err) 
  8.  } 
  9.  v, err := p.Lookup("V") 
  10.  if err != nil { 
  11.   panic(err) 
  12.  } 
  13.  f, err := p.Lookup("F") 
  14.  if err != nil { 
  15.   panic(err) 
  16.  } 
  17.  
  18.  *v.(*int) = 999 
  19.  f.(func())() 

输出结果:

  1. 脑子进了 999 次煎鱼  

在程序中,我们先调用了 plugin.Open 方法打开了前面所编译的 plugin.so 动态库。

紧接着调用 plugin.Lookup 方法,定位到了变量 V 和 方法 F,但由于其返回值都是 Symbol(interface),因此我们需要对其进行类型断言,随时才可以调用和使用。

至此完成了一个插件的基本使用。

为什么不被需要

在前面我们提到了大量 Go Plugin 的优点,也演示了其 Plugin 代码编写起来有多么的简单和方便。

但,为什么 Go Plugin 已经发布了 4 年依然没有被大规模应用,甚至对于不少业务开发来讲是不被需要的呢,或是压根不知道有这东西?

究其原因,我个人认为一个东西的广泛应用要至少符合以下三大点:

  • 基数:需要的场景多。
  • 上手:方便且易用。
  • 质量:没有大问题。

比较折腾的人的是,Go Plugin 这三大点都欠一些火候,综合导致了该功能的没有大规模应用。

像是要应用 Go Plugin 有诸如下约束:

  • 环境问题:不支持 Windows 等(暂无计划,#19282),MacOS 有些问题,一开始只支持 Linux,其他的也是后面慢慢增加的支持。
  • Go 版本问题:Plugin 构建环境和第三方包的依赖版本需要保持一致。
  • 特性问题:Plugin 特性的缺失,例如不支持插件的关闭,暂时无新计划支持(#20461)。

总结

在 Go issues 中畅游时,能看到许多小伙伴在以往 4 年踩过的坑和无奈。甚至有一个高赞回答(#19282)表示:插件功能主要是一个技术演示,由于一些不道德的原因,被作为语言的稳定功能发布(The plugin feature is mostly a tech demo that for some unholy reason got released as a stable feature of the language.)。

目前 Go Plugin 并不是 Go Team 的优先事项,在 Windows/Mac 的支持存在问题。GOPATH 有问题,不同 GO 版本也有问题。更是建议如果您想要插件,请走较慢的 grpc 路线,因为它们是有效的插件。

也可以参考为数不多的一些 Go Plugin 用户的方案,例如:tidb,甚至写了个指导文档。

但如果要在生产正式使用,劝你还是需要慎重考虑,又或是再等等...等更完善的那一天?

参考

Go Package plugin

Why is there no windows support for plugins?

plugin: add Windows support

plugin: Add support for closing plugins

如何评价 Go 标准库中新增的 plugin 包?

 

一文搞懂Go语言的plugin

 

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...