21

在golang中使用lua脚本

 5 years ago
source link: https://studygolang.com/articles/19703?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

lua基础

注释:

-- this is a comment

声明全局变量:

x = 123

声明本地变量:

local y = 456

方法声明:

function hello_world()
 return "Hello World"
end

迭代:

for i = 1, 10 do
   print(i)
end

条件:

if x == 123 then
    print("x is the magic number")
else
    print("I have no idea what x is")
end

字符串连接:

print("Hello" .. " World")

作为数组使用一个table — 数组的索引从1开始:

data_types = {1.0, 123, "redis", true, false, hello_world}
print(data_types[3]) -- the output is "redis"

作为hash使用一个table:

languages = {lua = 1993, javascript = 1995, python = 1991, ruby =1995}
print("Lua was created in " .. languages["lua"])
print("JavaScript was created in " .. languages.javascript)

redis脚本执行是一种原子操作,所以在执行期间redis服务会被阻塞。默认脚本操作会有5秒的执行时间

当一个lua脚本执行超时不会自动停止,它会开始对每一个命令回复一个busy状态,表明脚本正在运行。使用命令 SCRIPT KILL 或者 SHUTDOWN NOSAVE 终止脚本执行才能使redis服务回到正常状态

举个栗子

package main

import (
    "fmt"
    "github.com/go-redis/redis"
)

var Client *redis.Client

func init() {
    Client = redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })
}

//noinspection GoInvalidCompositeLiteral
func main() {

    Client.FlushAll()

    Client.Set("foo", "bar" , 0)

    var luaScript = redis.NewScript(`return redis.call("GET" , KEYS[1])`)

    n , err := luaScript.Run(Client , []string{"foo"}).Result()
    if err != nil {
        panic(err)
    }

    fmt.Println(n , err)

}

另一个栗子

package main

import (
    "fmt"
    "github.com/go-redis/redis"
)

var Client *redis.Client

func init() {
    Client = redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })
}

//noinspection GoInvalidCompositeLiteral
func main() {

    Client.FlushAll()

    foo := []redis.Z{
        {
            1732, "George Washington",
        },
        {
            1809, "Abraham Lincoln",
        },
        {
            1858, "Theodore Roosevelt",
        },
    }

    Client.ZAdd("presidents", foo...)

    var luaScript = redis.NewScript(`
        local elements = redis.call("ZRANGE" , KEYS[1] , 0 , 0) 
        redis.call("ZREM" , KEYS[1] , elements[1])
        return elements[1]
    `)

    n , err := luaScript.Run(Client , []string{"presidents"} , 1).Result()
    if err != nil {
        panic(err)
    }

    fmt.Println(n , err)

}

使用evalsha来操作lua

当执行脚本多次的时候,可以使用 SCRIPT LOADEVALSHA 代替 EVAL 有可能节省带宽。命令 SCRIPT LOAD 缓存一个lua脚本,同时返回一个sha1的标识符。命令 EVALSHA 基于sha1的标识符执行脚本,通过 SCRIPT LOAD 返回。使用 EVALSHA 只有标识符通过网络传输,而不是一个lua代码块

继续举个栗子

package main

import (
    "fmt"
    "github.com/go-redis/redis"
)

var Client *redis.Client

func init() {
    Client = redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })
}

//noinspection GoInvalidCompositeLiteral
func main() {

    Client.FlushAll()

    Client.Set("foo" , "bar" , -1)

    var luaScript = `return redis.call("INFO")`
    result ,err := Client.ScriptLoad(luaScript).Result()   //返回的脚本会产生一个sha1哈希值,下次用的时候可以直接使用这个值,类似于
    if err != nil {
        panic(err)
    }

    foo :=Client.EvalSha(result ,[]string{})
    fmt.Println(foo.Val())
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK