当前位置: 首页 > news >正文

golang 动态库

目录

  • 1. golang 动态库
  • 2. golang 语言使用动态库、调用动态链接库
    • 2.1. Go 插件系统
    • 2.2. 动态加载的优劣
    • 2.3. Go 的插件系统:Plugin
    • 2.4. 插件开发原则
      • 2.4.1. 插件独立
      • 2.4.2. 使用接口类型作为边界
      • 2.4.3. Unix 模块化原则
      • 2.4.4. 版本控制
    • 2.5. 插件开发示例
      • 2.5.1. 编写插件
      • 2.5.2. 使用插件

1. golang 动态库

2. golang 语言使用动态库、调用动态链接库

2.1. Go 插件系统

通过使用插件在运行时扩展程序的功能,而无需重新编译程序,这是一个很常见的功能需求,特别是在模块化设计的程序里面,比如 Nginx 的模块系统。 在 C/C++中通过使用动态库的方式可以实现动态加载,但是 Go 直到 1.8 官方才开始支持,下面将介绍 Go 如何基于动态链接库来实现动态加载。

2.2. 动态加载的优劣

优点:

  • 动态加载,也称热加载,每次升级时不用重新编译整个工程,重新部署服务,而是添加插件时进行动态更新。这对于很多比较重型的服务来说非常重要。

缺点:

  • 带来一定的安全风险,如果一些非法模块被注入如何防范
  • 给系统带来一定的不稳定的因素,如果模块有问题,没有经过良好的测试,容易导致服务崩溃
  • 为版本管理带来了难题,特别是在微服务的今天,同一个服务,加载了不同的插件,应该怎么管理版本,插件版本应该如何管理

因此请慎重考虑,是使用动态插件还是在源码里面进行插件化。

2.3. Go 的插件系统:Plugin

从 1.8 版开始,官方提供了这种插件化的手段:plugin. 此功能使程序员可以使用动态链接库构建松散耦合的模块化程序,可以在运行时动态加载和绑定。

Go 插件是使用 -buildmode = plugin 标记编译的一个包,用于生成一个共享对象 (.so) 库文件。 Go 包中的导出的函数和变量被公开为 ELF 符号,可以使用 plugin 包在运行时查找并绑定 ELF 符号。Go 编译器能够使用 build flag -buildmode = c-shared 创建 C 风格的动态共享库。

1.8 版本插件功能只能在 Linux 上使用。 1.10 也可以在 Mac 上运行。

下面将介绍使用 Go 插件系统创建模块化软件的一些开发原则,并提供一个功能齐全的示例。

2.4. 插件开发原则

使用 Go 插件创建模块化程序需要遵循与常规 Go 软件包一样严格的软件实践。然而,插件引入了新的设计问题,因为它们的解耦性质被放大了。因此我们在设计可插拔系统时,有一些原则需要关注:

2.4.1. 插件独立

应该将插件视为与其他组件分离的独立组件。这允许插件独立于他们的消费者,并拥有自己的开发和部署生命周期。注意插件的可用性很重要,因为它有肯能为整个系统带来不稳定的因素,因此系统必须为插件集成提供一个简单的封装层,插件开发人员将系统视为黑盒,不作为所提供的合约以外的假设,从而保证插件自身的可用性。

2.4.2. 使用接口类型作为边界

Go 插件可以导出任何类型的包函数和变量。您可以设计插件来将其功能解耦为一组松散的函数。缺点是您必须单独查找和绑定每个函数符号。
然而,更为简单的方法是使用接口类型。创建导出功能的接口提供了统一简洁的交互,并具有清晰的功能划分。解析到接口的符号将提供对该功能的整个方法集的访问,而不仅仅是一个方法。

2.4.3. Unix 模块化原则

插件代码应该设计成只关注一个功能点。

2.4.4. 版本控制

插件是不透明而独立的实体,应该进行版本控制,以向用户提示其支持的功能。这里的一个建议是在命名共享对象文件时使用语义版本控制。例如,上面的文件编译插件可以命名为 eng.so.1.0.0。

2.5. 插件开发示例

我以我遇到的一个实际需求为例,在开发物联网接入组件的时候,需要动态支持物解析,下面就开发一个物解析的插件系统。

下面是项目结构,parser.go 是接口规约,main.go 是主程序,plugins 存放多个插件包

├── main.go
├── parser.go
└── plugins├── car│   └── car.go└── phone└── phone.go

2.5.1. 编写插件

  • 编写主程序接口规约:main.go
package main// Parser use to parse things
type Parser interface {
byte) (meta map[string]string, data map[string]float64, err error)
}
  • 根据接口规约编写插件:car.go
package maintype car stringfunc (c *car) Parse([]byte) (meta map[string]string, data map[string]float64, err error) {
map[string]string{"key1": "a"}
map[string]float64{"key1": 1}return meta, data, nil
}var Car car
  • 根据接口规约编写插件:phone.go
package maintype phone stringfunc (p *phone) Parse([]byte) (meta map[string]string, data map[string]float64, err error) {
map[string]string{"key1": "b"}
map[string]float64{"key1": 2}return meta, data, nil
}var Phone phone
  • 编译插件插件写完后将在 plugins 目录下编译插件:
$ cd plugins
$ go build -buildmode=plugin -o car.so car/car.go
$ go build -buildmode=plugin -o phone.so phone/phone.go

最终在 plugins 目录下会生成好我们编译好的插件:

$ ls *.so
car.so   phone.so

2.5.2. 使用插件

插件的使用很简单,大概步骤如下:

  • 用 plugin.Open() 打开插件文件
  • 用 plguin.Lookup(“Export-Variable-Name”) 查找导出的符号”Car”或者”Phone”。 请注意,符号名称与插件模块中定义的变量名称相匹配
  • 使用该变量

主程序使用插件:main.go

package mainimport (
"fmt"
"plugin"
)// Parser use to parse things
type Parser interface {
byte) (meta map[string]string, data map[string]float64, err error)
}func pa() {
"./plugins/car.so")
if err != nil {
panic(err)}"Car")
if err != nil {
panic(err)}p, ok := car.(Parser)
if ok {
byte("a"))
if err != nil {
panic(err)}
"meta: %v, data: %v \n", meta, data)}
}func pb() {
"./plugins/phone.so")
if err != nil {
panic(err)}"Phone")
if err != nil {
panic(err)}p, ok := phone.(Parser)
if ok {
byte("a"))
"meta: %v, data: %v \n", meta, data)}
}func main() {pa()pb()
}

测试是否正常运行:

$ go run main.go
meta: map[key1:a], data: map[key1:1]
meta: map[key1:b], data: map[key1:2]

相关文章:

golang 动态库

目录 1. golang 动态库2. golang 语言使用动态库、调用动态链接库2.1. Go 插件系统2.2. 动态加载的优劣2.3. Go 的插件系统:Plugin2.4. 插件开发原则2.4.1. 插件独立2.4.2. 使用接口类型作为边界2.4.3. Unix 模块化原则2.4.4. 版本控制 2.5. 插件开发示例2.5.1. 编写…...

Python的2042小游戏及其详解

源码: import random import os# 游戏界面尺寸 SIZE 4# 游戏结束标志 GAME_OVER False# 初始化游戏界面 board [[0] * SIZE for _ in range(SIZE)]# 随机生成一个初始方块 def add_random_tile():empty_tiles [(i, j) for i in range(SIZE) for j in range(SIZ…...

怎么去掉邮件内容中的回车符

上图是Outlook 截图,可见1指向的总有回车符; 故障原因: 不小心误按了箭头4这个选项; 解决方法: 点击2箭头确保tab展开; 点击3以找到箭头4. 取消勾选或者多次点击,即可解决。...

Git-概念与架构

GIT-概念与架构 一、背景和起源二、版本控制系统1.版本控制分类1.1 集中式版本控制1.2 分布式版本控制 2.Git和SVN对比2.1 SVN2.2 GIT 三、GIT框架1.工作区(working directory)2.暂存区(staging area)3.本地仓库(local…...

android 数独小游戏 经典数独·休闲益智

一款经典数独训练app 标题资源下载 (0积分)https://download.csdn.net/download/qq_38355313/88544810 首页页面: 1.包含有简单、普通、困难、大师四种难度的数独挑战供选择; 记录页面: 1.记录用户训练过的数独信息&…...

GAT里面的sofamax函数的实现:

1.sofamx 公式: 2. GAT里的sofamax函数的实现: 1. 因为指数在x轴正轴爆炸式地快速增长,如果zi比较大,exp⁡(zi)也会非常大,得到的数值可能会溢出。溢出又分为下溢出(Underflow)和上溢出&#x…...

Idea 编译SpringBoot项目Kotlin报错/Idea重新编译

原因应该是一次性修改了大量的文件, SpringBoot项目启动Kotlin报错, Build Project也是同样的结果, 报错如下 Error:Kotlin: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.9.0, expected version is 1.1.13. Build-&…...

【Qt之QWizard问题】setPixmap()设置logo、background、watermark无效不显示解决方案

问题原因: 使用QWizard或者QWizardPage设置像素图,结果设置完不显示效果。 设置示例: setPixmap(QWizard::WatermarkPixmap, QPixmap("xxx/xxx/xxx.png"));setPixmap(QWizard::BackgroundPixmap, QPixmap("xxx/xxx/xxx.png&…...

mysql 设置远程登录

为了允许远程连接到MySQL服务器,你需要采取以下步骤: 编辑MySQL配置文件: 打开MySQL的配置文件 my.cnf 或 my.ini,这取决于你的操作系统和MySQL版本。该文件通常位于MySQL安装目录下的 etc 或 etc/mysql 目录中。 添加或确保以下行…...

ES的索引概念

1. 概念:Elasticsearch(ES)是一个开源的全文搜索引擎,可以快速地存储、搜索和分析大量的结构化和非结构化数据。 2. 索引的作用:ES索引是将数据存储在Elasticsearch中的基本方式。它用于存储、搜索、分析和查询数据。…...

text/xml和application/xml

困惑 在http消息中,同样是传送xml信息,有的时候看到Content-Type的值是text/xml,有的时候值是application/xml,感到困惑。 例如,用Postman发送http消息给Tomcat中的基于JAX-WS的 web服务: 请求中传送了xm…...

鸿蒙4.0正式版升级机型

官网支持升级机型入口:HarmonyOS 4支持机型 | 华为官网 (huawei.com) 正式版 手机 HUAWEI P60 HUAWEI P60 Pro HUAWEI P60 Art HUAWEI Mate X3 HUAWEI Mate X3 典藏版 HUAWEI Mate 50 HUAWEI Mate 50 Pro HUAWEI Mate 50 RS 保时捷设计 HUAWEI Mate 50E …...

架构开发与优化咨询和实施服务

服务概述 得益于硬件平台算力的提升,汽车电子电气架构的集成度逐渐提高,从单体ECU、到功能域集成控制器、到区域集成控制器,多域融合成为了目前行业中软件工程的重要工作内容。同时,在传统控制器C代码开发的基础上,C、…...

react hook ts 实现 列表的滚动分页加载,多参数混合混合搜索

InfiniteScroll 的组件见: https://blog.csdn.net/Zhooson/article/details/134396945 search.tsx 页面 import { FC, useEffect, useState } from react import InfiniteScroll from ../../components/InfiniteScrollconst tabs [{id: 1,title: tab-1,index: 1…...

Java应用如何不改代码,调整窗口大小

最近工作上遇到了这个问题,浅浅的研究了一点,这里记录一下。 有不同意见欢迎评论区交流。 需求 项目需求: 客户已经开发好了应用,不过应用在系统上看起来有点小,希望应用能在不修改代码的情况下,通过其他…...

汽车 CAN\CANFD数据记录仪

CAN FD数据记录仪解决汽车电子数据记录与偶发性故障查找问题。 1、脱机离线记录两路CAN/CANFD通道数据 脱机离线记录两路CAN/CANFD通道数据,可记录6个月数据。每个通 道单独设置触发记录模式、触发前预记录报文个数(默认1000帧)及 过滤规则&a…...

Kafka中topic(主题)、broker(代理)、partition(分区)和replication(副本)它们的关系

在Apache Kafka中,有四个重要的概念:topic(主题)、broker(代理)、partition(分区)和replication(副本)。它们的关系如下: Topic(主题&…...

Mysql字符串类型编码问题

Q: 数据库 Redis 出现 字符比较不一致问题 A:调查后发现在数据库中使用的 account 编码为 utf8mb4_unicode_ci,而这种其实是不区分大小写的,后面我们根据情况,将编码换为 utf8mb4_bin就可以了 参考: utf8mb4_Sageice的博客-CSDN博客 MySQ…...

LabVIEW关于USRPRIO的示例代码

LabVIEW关于USRPRIO的示例代码 USRPRIO 通常以两种方式使用: 1 基于 FPGA 的编程 对于希望修改USRP上的底层FPGA代码以添加自定义DSP模块的应用,请使用USRP示例项目。它可作为构建 USRP RIO 流式处理应用程序的起点,可从“创建项目”对话框…...

【深度学习实验】网络优化与正则化(六):逐层归一化方法——批量归一化、层归一化、权重归一化、局部响应归一化

文章目录 一、实验介绍二、实验环境1. 配置虚拟环境2. 库版本介绍 三、优化算法0. 导入必要的库1. 随机梯度下降SGD算法a. PyTorch中的SGD优化器b. 使用SGD优化器的前馈神经网络 2.随机梯度下降的改进方法a. 学习率调整b. 梯度估计修正 3. 梯度估计修正:动量法Momen…...

Cursor实现用excel数据填充word模版的方法

cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...

PH热榜 | 2025-06-08

1. Thiings 标语:一套超过1900个免费AI生成的3D图标集合 介绍:Thiings是一个不断扩展的免费AI生成3D图标库,目前已有超过1900个图标。你可以按照主题浏览,生成自己的图标,或者下载整个图标集。所有图标都可以在个人或…...

字符串哈希+KMP

P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...