golua虛擬機的使用分析,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
創(chuàng)新互聯(lián)公司專業(yè)IDC數(shù)據(jù)服務器托管提供商,專業(yè)提供成都服務器托管,服務器租用,成都棕樹電信機房,成都棕樹電信機房,成都多線服務器托管等服務器托管服務。
之前一直想把openflow這樣的分布式流程系統(tǒng)做起來,但是時間和應用場景的問題所以都是做了一個半拉子工程,而且之前想的也有點簡單了,認為只要有同學愿意,在開發(fā)上應該沒問題,但是最終還是出現(xiàn)了項目管理和開發(fā)能力的問題,最終擱淺了。但是我想做一個分布式流程調(diào)度系統(tǒng)的想法一直沒有斷,其實在公司內(nèi)和另外一個同學做過一個flow系統(tǒng),也在線上使用了,直到現(xiàn)在還在使用。前一段時間就想把這個系統(tǒng)再優(yōu)化梳理一下,目標是做一個小巧的開源可用版本。經(jīng)過一段時間的梳理目前已經(jīng)初步完成了,后臺+前端代碼的重新梳理也已經(jīng)完成了。
而今天主要想寫的是其中使用到的一個技術點:lua。內(nèi)部版本我們使用的是golang開發(fā),但是在執(zhí)行中為了保證流程之間不會互相影響,我們使用lua虛擬機技術;讓每個流程在執(zhí)行的時候在一個獨立的lua虛擬機中執(zhí)行。內(nèi)部版本使用golua這個組件,但是這個組件有個問題,它其實是一個cgo的版本,就是它其實上是調(diào)用本地lua庫來執(zhí)行,所在在編譯部署和執(zhí)行上都有一定的效率問題。
所以在新開發(fā)的版本上我想使用其它的方式,在研究了一段時間后決定使用gopher-lua這個組件,這個是使用golang重寫的支持Lua5.1的虛擬機,在執(zhí)行上可以直接golang無縫結合,有非常好的go的api接口,在使用上也流暢很多,在實現(xiàn)思路上也采用golang的一些思路,和golang結合更好。也通過這次學習了一把lua,才發(fā)現(xiàn)這個技術確實很牛,據(jù)統(tǒng)計lua的c實現(xiàn)代碼才1w行左右,但是執(zhí)行非常高效,而且lua的預留關鍵字也非常少??梢哉f是一個非常簡潔又高效的語言。
在我這個flow項目非常合適,所以用gopher-lua替換了golua,因為gopher-lua的api和類型支持比golua要好很多,所以在替換后精簡了不少代碼。下面就介紹一下項目中使用到的一些關鍵點。
在使用上api非常簡單,主要有以下幾步:
引入gopher-lua
創(chuàng)建虛擬機
使用虛擬機執(zhí)行l(wèi)ua語句或lua腳本文件
關閉虛擬機
package mainimport lua "github.com/yuin/gopher-lua" // 1.引入gopher-luafunc main() { L := lua.NewState() // 2.創(chuàng)建一個lua解釋器實例defer L.Close() // 4.關閉虛擬機if err := L.DoString(`print("hello")`); err != nil { // 3.用創(chuàng)建的虛擬機來執(zhí)行l(wèi)ua語句 // if err := L.DoFile("hello.lua"); err != nil { // 3.用創(chuàng)建的虛擬機來執(zhí)行l(wèi)ua腳本文件panic(err) } }
api在使用上還是非常簡單的。其它關于基本數(shù)據(jù)類型的這里就不多介紹了,在其github站點上有非常詳細的介紹。
下面將主要介紹2個在flow項目中用到的非常有用的功能點。
用golang寫的服務,如果我們要使用lua腳本中定義的函數(shù)怎么辦呢?在gopher-lua提供了響應的方法,在其站點也有非常好的例子來說明:
首先用DoFile方法來加載lua腳本,在腳本中定義需要lua函數(shù)
其次使用CallByParam函數(shù)進行調(diào)用
L := lua.NewState()defer L.Close()if err := L.DoFile("double.lua"); err != nil { panic(err) }if err := L.CallByParam(lua.P{ Fn: L.GetGlobal("double"), // 獲取double這個函數(shù)的引用 NRet: 1, // 指定返回值數(shù)量 Protect: true, // 如果出現(xiàn)異常,是panic還是返回err }, lua.LNumber(10)); err != nil { // 傳遞輸入?yún)?shù):10 panic(err) } ret := L.Get(-1) // 獲取返回結果值L.Pop(1) // 從堆棧中扔掉返回結果
GopherLua的函數(shù)調(diào)用是通過堆棧來進行的,調(diào)用前把需要傳遞給函數(shù)的參數(shù)壓到棧里,函數(shù)執(zhí)行完成之后再將結果放入堆棧中,調(diào)用方通過在堆棧頂部拿函數(shù)執(zhí)行結果。
go調(diào)用lua函數(shù)在flow項目中用的相對較少,用的較多的是下面一種:lua腳本中調(diào)用go函數(shù);因為很多復雜操作其實用lua來做還是有點復雜和不安全,尤其有些公共操作或者復雜的db操作。所以好的做法是在go中把函數(shù)封裝好,再在外部寫lua腳本,執(zhí)行的時候可以調(diào)用go函數(shù),這樣既可以滿足lua腳本的靈活性,也極大的擴展了lua的能力和減低了編寫復雜度。
先看看其基本使用方法,也是通過官網(wǎng)的例子來說明。
func Double(L *lua.LState) int { lv := L.ToInt(1) // 獲取七個參數(shù) L.Push(lua.LNumber(lv * 2)) // 把計算結果壓棧 return 1 // 返回計算返回參數(shù)的個數(shù)}func main() { L := lua.NewState() defer L.Close() L.SetGlobal("double", L.NewFunction(Double)) // 注冊函數(shù)}
首先再gopher-lua中有一個類型lua.LGFunction ,這個類型就是一個函數(shù)類型,它固定了函數(shù)的入?yún)⒑统鰠?,入?yún)⒕褪莑ua.LState的一個引用,返回值就是一個int。如下面的定義,如果需要跟多的參數(shù)就需要使用堆棧或者對lua.LState擴展成員的方式。在執(zhí)行完成之后也是通過堆?;蛘邔ua.LState擴展成員的方式把返回值傳遞出去。
函數(shù)的注冊有多種方式,上面是一種方式,另外我從網(wǎng)上還看到一種方式,就是使用lua的table的方式。
myfuns := L.NewTable() L.SetGlobal("myfuns", myfuns) // 注冊函數(shù) L.SetField(myfuns, "gofun1", L.NewFunction(gofun1)) .... // 調(diào)用方式 err := L.DoString(` test = myfuns:gofun1("test") `)
這里面不方便的一點就是參數(shù)的傳遞和獲取不是很直觀,很多時候需要二次分裝調(diào)用函數(shù)。這一點有點不方便。其它還好。
GopherLua可以創(chuàng)建一個非常干凈的Lua解釋器實例,不加載任何系統(tǒng)模塊。然后由程序員自己提供的模塊注冊進去,給內(nèi)嵌腳本提供一個安全的沙箱運行環(huán)境。
關于golua虛擬機的使用分析問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關知識。
網(wǎng)站題目:golua虛擬機的使用分析
網(wǎng)址分享:http://www.rwnh.cn/article6/jgpoog.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供虛擬主機、網(wǎng)站改版、電子商務、網(wǎng)站收錄、網(wǎng)站建設、關鍵詞優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)