Golang官方如何支持加载动态库

来源:互联网 发布:网络舆论的传播分析 编辑:程序博客网 时间:2024/06/08 17:24

Golang1.8官方支持加载动态库了,而且看起来功能很强大。 文档上面描述Plugin功能是协程并发安全的,而且支持高级数据类型(包括chan),同时不需要写任何C代码(以前或多或少需要写一些)。

下面我们通过一些demo来看看如何使用golang plugin功能

入门

下面是一个简单的plugin 代码:

package main// // No C code needed.import "C"import (    "fmt")var V intfunc F() { fmt.Printf("Hello, number %d\n", V) }

这是官方提供的例子,以后我们再慢慢扩展。

go build -buildmode=plugin  main.go  //main.go是plugin文件名称,你可以改成其它名

你会看到多出一个main.so动态库。

然后我们开始调用这个动态库

package mainimport (    "plugin")func main() {    p, err := plugin.Open("main.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())() 

正常编译这个go文件,然后执行它就可以看到屏幕会输出

Hello, number 7

这只是最简单的形式,下面我们增加一些难度,使用一些复杂数据类型。

使用复杂类型

我们自定义一个结构体

package datatype VS struct {    Name   string    Age    int    School string}

这里需要注意,必须要把结构体放到另外一个package中,否则build plugin时,会抱结构体找不到。

然后我们开始修改plugin代码

package main// // No C code needed.import "C"import (    "fmt"    "temp/data")var V intfunc F() { fmt.Printf("Hello, number %d\n", V) }var Vs data.VSfunc ComplexType() {    fmt.Println(Vs.Name, Vs.Age, Vs.School)}

我们声明了VS结构体,然后增加了一个函数用来使用结构体(需要重新编译plugin)。 调用方也需要同步修改

package mainimport (    "plugin"    "temp/data")func main() {    p, err := plugin.Open("main.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"    vs, err := p.Lookup("Vs")    if err != nil {        panic(err)    }    ct, err := p.Lookup("ComplexType")    if err != nil {        panic(err)    }    *vs.(*data.VS) = data.VS{        Name:   "DATA",        Age:    11,        School: "BEIDA",    }    ct.(func())()}

在main中我们构建了一个VS结构体,然后给各个属性赋值。 如果正常,你将看到如下的信息

Hello, number 7DATA 11 BEIDA

到此为止,我们已经可以在Plugin中使用高级复杂结构体了,可以说已经满足50%需求了。 但探索无止境,如果调用和Plugin之间需要互相通讯怎么办?下面我们看看Plugin是否支持Chan。

支持Chan

首先声明一个全局Chan

package datatype VS struct {    Name   string    Age    int    School string}var Msg = make(chan VS)

不但声明了一个全局chan,而且是高级类型的chan。 下面在Plugin中使用chan

package main// // No C code needed.import "C"import (    "fmt"    "temp/data")var V intfunc F() { fmt.Printf("Hello, number %d\n", V) }var Vs data.VSfunc ComplexType() {    fmt.Println(Vs.Name, Vs.Age, Vs.School)    Vs.Age = Vs.Age * 4    data.Msg <- Vs}

Plugin接收到vs数据后,将AGE放大4倍在扔出去(扔哪里就不管了)(需要重新编译plugin)。 再修改一下调用函数:

package mainimport (    "plugin"    "temp/data")func main() {    p, err := plugin.Open("main.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"    vs, err := p.Lookup("Vs")    if err != nil {        panic(err)    }    ct, err := p.Lookup("ComplexType")    if err != nil {        panic(err)    }    *vs.(*data.VS) = data.VS{        Name:   "DATA",        Age:    11,        School: "BEIDA",    }    go ct.(func())()    select {    case m := <-data.Msg:        println(m.Age)    }}

其实是在main函数中接受扔回来的VS结构体。 编译之后再执行,可以看到

Hello, number 7DATA 11 BEIDA44

OK,执行正常,符合预期。 这里先提供plugin如何使用,以后我们再剖析一下Golang是如何实现这些功能的。


0 0
原创粉丝点击