加入收藏 | 设为首页 | 会员中心 | 我要投稿 常州站长网 (https://www.0519zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 建站资源 > 优化 > 正文

当Go遇上了Lua,会发生什么

发布时间:2019-03-16 13:10:00 所属栏目:优化 来源:Jiahonzheng
导读:副标题#e# 在 GitHub 玩耍时,偶然发现了 gopher-lua ,这是一个纯 Golang 实现的 Lua 虚拟机。我们知道 Golang 是静态语言,而 Lua 是动态语言,Golang 的性能和效率各语言中表现得非常不错,但在动态能力上,肯定是无法与 Lua 相比。那么如果我们能够将二
副标题[/!--empirenews.page--]

当Go遇上了Lua,会发生什么

在 GitHub 玩耍时,偶然发现了 gopher-lua ,这是一个纯 Golang 实现的 Lua 虚拟机。我们知道 Golang 是静态语言,而 Lua 是动态语言,Golang 的性能和效率各语言中表现得非常不错,但在动态能力上,肯定是无法与 Lua 相比。那么如果我们能够将二者结合起来,就能综合二者各自的长处了(手动滑稽。

在项目 Wiki 中,我们可以知道 gopher-lua 的执行效率和性能仅比 C 实现的 bindings 差。因此从性能方面考虑,这应该是一款非常不错的虚拟机方案。

Hello World

这里给出了一个简单的 Hello World 程序。我们先是新建了一个虚拟机,随后对其进行了 DoString(...) 解释执行 lua 代码的操作,最后将虚拟机关闭。执行程序,我们将在命令行看到 "Hello World" 的字符串。

  1. package main  
  2. import (  
  3.     "github.com/yuin/gopher-lua"  
  4. )  
  5. func main() {  
  6.     l := lua.NewState()  
  7.     defer l.Close()  
  8.     if err := l.DoString(`print("Hello World")`); err != nil {  
  9.         panic(err)  
  10.     }  
  11. }  
  12. // Hello World 

提前编译

在查看上述 DoString(...) 方法的调用链后,我们发现每执行一次 DoString(...) 或 DoFile(...) ,都会各执行一次 parse 和 compile 。

  1. func (ls *LState) DoString(source string) error {  
  2.     if fn, err := ls.LoadString(source); err != nil {  
  3.         return err  
  4.     } else {  
  5.         ls.Push(fn)  
  6.         return ls.PCall(0, MultRet, nil)  
  7.     }  
  8. }  
  9. func (ls *LState) LoadString(source string) (*LFunction, error) {  
  10.     return ls.Load(strings.NewReader(source), "<string>")  
  11. }  
  12. func (ls *LState) Load(reader io.Reader, name string) (*LFunction, error) {  
  13.     chunk, err := parse.Parse(reader, name)  
  14.     // ...  
  15.     proto, err := Compile(chunk, name)  
  16.     // ...  

从这一点考虑,在同份 Lua 代码将被执行多次(如在 http server 中,每次请求将执行相同 Lua 代码)的场景下,如果我们能够对代码进行提前编译,那么应该能够减少 parse 和 compile 的开销(如果这属于 hotpath 代码)。根据 Benchmark 结果,提前编译确实能够减少不必要的开销。

  1. package glua_test  
  2. import (  
  3.     "bufio"  
  4.     "os"  
  5.     "strings"  
  6.     lua "github.com/yuin/gopher-lua"  
  7.     "github.com/yuin/gopher-lua/parse"  
  8. )  
  9. // 编译 lua 代码字段  
  10. func CompileString(source string) (*lua.FunctionProto, error) {  
  11.     reader := strings.NewReader(source)  
  12.     chunk, err := parse.Parse(reader, source)  
  13.     if err != nil {  
  14.         return nil, err  
  15.     }  
  16.     proto, err := lua.Compile(chunk, source)  
  17.     if err != nil {  
  18.         return nil, err  
  19.     }  
  20.     return proto, nil  
  21. }  
  22. // 编译 lua 代码文件  
  23. func CompileFile(filePath string) (*lua.FunctionProto, error) {  
  24.     file, err := os.Open(filePath)  
  25.     defer file.Close()  
  26.     if err != nil {  
  27.         return nil, err  
  28.     }  
  29.     reader := bufio.NewReader(file)  
  30.     chunk, err := parse.Parse(reader, filePath)  
  31.     if err != nil {  
  32.         return nil, err  
  33.     }  
  34.     proto, err := lua.Compile(chunk, filePath)  
  35.     if err != nil {  
  36.         return nil, err  
  37.     }  
  38.     return proto, nil  
  39. }  
  40. func BenchmarkRunWithoutPreCompiling(b *testing.B) {  
  41.     l := lua.NewState()  
  42.     for i := 0; i < b.N; i++ {  
  43.         _ = l.DoString(`a = 1 + 1`)  
  44.     }  
  45.     l.Close()  
  46. }  
  47. func BenchmarkRunWithPreCompiling(b *testing.B) {  
  48.     l := lua.NewState()  
  49.     proto, _ := CompileString(`a = 1 + 1`)  
  50.     lfunc := l.NewFunctionFromProto(proto)  
  51.     for i := 0; i < b.N; i++ {  
  52.         l.Push(lfunc) 
  53.          _ = l.PCall(0, lua.MultRet, nil)  
  54.     }  
  55.     l.Close()  
  56. }  
  57. // goos: darwin  
  58. // goarch: amd64  
  59. // pkg: glua  
  60. // BenchmarkRunWithoutPreCompiling-8         100000             19392 ns/op           85626 B/op         67 allocs/op  
  61. // BenchmarkRunWithPreCompiling-8           1000000              1162 ns/op            2752 B/op          8 allocs/op  
  62. // PASS  
  63. // ok      glua    3.328s 

虚拟机实例池

在同份 Lua 代码被执行的场景下,除了可使用提前编译优化性能外,我们还可以引入虚拟机实例池。

(编辑:常州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读