UDN-企业互联网技术人气社区

板块导航

浏览  : 1744
回复  : 0

[干货] Golang官方如何支持加载动态库

[复制链接]
开花包的头像 楼主
发表于 2017-1-3 15:34:13 | 显示全部楼层 |阅读模式
  Golang1.8官方支持加载动态库了,而且看起来功能很强大。 文档上面描述Plugin功能是协程并发安全的,而且支持高级数据类型(包括chan),同时不需要写任何C代码(以前或多或少需要写一些)。

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

  入门

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

  1.   package main

  2.   // // No C code needed.

  3.   import "C"

  4.   import (

  5.   "fmt"

  6.   )

  7.   var V int

  8.   func F() { fmt.Printf("Hello, number %d\n", V) }
复制代码


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

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


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

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

  1.   package main

  2.   import (

  3.   "plugin"

  4.   )

  5.   func main() {

  6.   p, err := plugin.Open("main.so")

  7.   if err != nil {

  8.   panic(err)

  9.   }

  10.   v, err := p.Lookup("V")

  11.   if err != nil {

  12.   panic(err)

  13.   }

  14.   f, err := p.Lookup("F")

  15.   if err != nil {

  16.   panic(err)

  17.   }

  18.   *v.(*int) = 7

  19.   f.(func())()
复制代码


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

  
  1. Hello, number 7
复制代码

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

  使用复杂类型

  我们自定义一个结构体

  1.   package data

  2.   type VS struct {

  3.   Name string

  4.   Age int

  5.   School string

  6.   }
复制代码


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

  然后我们开始修改plugin代码

  1.   package main

  2.   // // No C code needed.

  3.   import "C"

  4.   import (

  5.   "fmt"

  6.   "temp/data"

  7.   )

  8.   var V int

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

  10.   var Vs data.VS

  11.   func ComplexType() {

  12.   fmt.Println(Vs.Name, Vs.Age, Vs.School)

  13.   }
复制代码


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

  1.   package main

  2.   import (

  3.   "plugin"

  4.   "temp/data"

  5.   )

  6.   func main() {

  7.   p, err := plugin.Open("main.so")

  8.   if err != nil {

  9.   panic(err)

  10.   }

  11.   v, err := p.Lookup("V")

  12.   if err != nil {

  13.   panic(err)

  14.   }

  15.   f, err := p.Lookup("F")

  16.   if err != nil {

  17.   panic(err)

  18.   }

  19.   *v.(*int) = 7

  20.   f.(func())() // prints "Hello, number 7"

  21.   vs, err := p.Lookup("Vs")

  22.   if err != nil {

  23.   panic(err)

  24.   }

  25.   ct, err := p.Lookup("ComplexType")

  26.   if err != nil {

  27.   panic(err)

  28.   }

  29.   *vs.(*data.VS) = data.VS{

  30.   Name: "DATA",

  31.   Age: 11,

  32.   School: "BEIDA",

  33.   }

  34.   ct.(func())()

  35.   }
复制代码


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

  1.   Hello, number 7

  2.   DATA 11 BEIDA
复制代码


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

  支持Chan

  首先声明一个全局Chan

  1.   package data

  2.   type VS struct {

  3.   Name string

  4.   Age int

  5.   School string

  6.   }

  7.   var Msg = make(chan VS)
复制代码


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

  1.   package main

  2.   // // No C code needed.

  3.   import "C"

  4.   import (

  5.   "fmt"

  6.   "temp/data"

  7.   )

  8.   var V int

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

  10.   var Vs data.VS

  11.   func ComplexType() {

  12.   fmt.Println(Vs.Name, Vs.Age, Vs.School)

  13.   Vs.Age = Vs.Age * 4

  14.   data.Msg <- Vs

  15.   }
复制代码


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

  1.   package main

  2.   import (

  3.   "plugin"

  4.   "temp/data"

  5.   )

  6.   func main() {

  7.   p, err := plugin.Open("main.so")

  8.   if err != nil {

  9.   panic(err)

  10.   }

  11.   v, err := p.Lookup("V")

  12.   if err != nil {

  13.   panic(err)

  14.   }

  15.   f, err := p.Lookup("F")

  16.   if err != nil {

  17.   panic(err)

  18.   }

  19.   *v.(*int) = 7

  20.   f.(func())() // prints "Hello, number 7"

  21.   vs, err := p.Lookup("Vs")

  22.   if err != nil {

  23.   panic(err)

  24.   }

  25.   ct, err := p.Lookup("ComplexType")

  26.   if err != nil {

  27.   panic(err)

  28.   }

  29.   *vs.(*data.VS) = data.VS{

  30.   Name: "DATA",

  31.   Age: 11,

  32.   School: "BEIDA",

  33.   }

  34.   go ct.(func())()

  35.   select {

  36.   case m := <-data.Msg:

  37.   println(m.Age)

  38.   }

  39.   }
复制代码


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

  1.   Hello, number 7

  2.   DATA 11 BEIDA

  3.   44
复制代码


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

原文作者:佚名  来源:开发者头条

相关帖子

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部