Ⅰ Redis中使用Lua
在一些互联网项目中,难免会设计到一些原子性操作,例如实时交易量的累加,分布式锁的实现,那么采用lua脚本可以帮助我们完成一个原子性的操作
Redis会使用相同的 Lua 解释器来运行所有命令。Redis 还保证以原子方式执行脚本:在执行脚本时不会执行其他脚本或 Redis 命令。
使用Lua脚本的好处有
基本用法
例如
返回结果
使用Lua实现分布式锁
加锁
解锁
Ⅱ Redis 中使用 Lua 脚本
Redis 本身已经提供了丰富的命令,但是直接用来处理一些复杂业务时可能还不够方便,会有一定的局限性。因此,在 Redis2.6 版本开始提供了对 Lua 脚本的支持,Lua 脚本的使用还是比较广泛的,比如商品秒杀、分布式锁等,使用 Lua 脚本可以带来以下的好处:
为了让例子更加的贴近实际应用,这里实现一个简单版的分布式锁。这里先用 Jedis 操作。
上边详细的介绍了分布式锁的实现过程,以及可能出现的问题,最终,我们决定删除锁的操作使用 Lua 脚本实现,对应的脚本如下:
Lua 脚本中执行具体的 Redis 命令,需要使用 redis.call() 方法, KEYS 表示客户端发起脚本执行命令时携带的 Redis key 的一个集合, ARGV 则是其它参数的一个集合,主意下标从1开始。结合我们的业务,这里的 KEYS[1] 则表示 lock , ARGV[1] 则是一个随机字符串。整个脚本的含义就是,如果客户端传递的 lock 的 value 和 Redis 中存储的一致,就删除 lock 。
Lua 脚本的语法还是比较简单的,具体内容可以自行学习。
前边的准备工作基本结束了,文章开始说过执行脚本有两种途径,下边我们具体来看:
这里使用 jedis.eval() 发送脚本到 Redis 服务器执行,后两个参数分别是 key 的集合,以及 value 参数的集合。
先将脚本以文件形式放到 Redis 里,例如这样:
然后通过如下命令让 Redis 服务器缓存脚本:
script load 命令会在 Redis 服务器缓存 Lua 脚本,并且脚本内容经过 SHA-1 签名算法处理后,会返回脚本内容的 SHA1 校验和的编码,然后在端调用时,传入编码字符串作为参数,这样 Redis 服务器就会执行对应缓存的脚本了,就不用了每次发送具体的脚本内容了。
还有两个比较有用的命令:
除了使用上边的命令缓存脚本、生成脚本的 SHA1 校验和的编码,还可以使用 Jedis 实现,但最终的 SHA1 编码内容是不同的:
实际的项目中,可能更多的会在 SpringBoot 项目中整合 Redis,此时执行 Lua 脚本的基本流程如下:
核心的类就是 DefaultRedisScript ,它实现了 RedisScript 接口。 execute() 方法最后一个参数是可变类型的,用来传递多个 value 参数。初次执行 execute() 方法时,其内部会自动缓存 Lua 脚本到 Redis 服务器;同时每次执行脚本时会根据脚本内容自动计算出对应的 SHA1 校验和的编码,去匹配、执行缓存的脚本。
具体的 SHA1 校验和的编码,可以在 execute() 方法执行后,使用 redisScript.getSha1() 查看。使用 SpringBoot 方式 执行 Lua 脚本生成的 SHA1 校验和的编码和前边直接使用 Jedis 生成的一致。
无论用那种方式在 Redis 中使用 Lua 脚本,其中的原理都是类似的。
Ⅲ redis使用lua
redis中执行lua可以通过两种方式:
第一种是将lua脚本或命令直接使用redis执行,第二种相当于把脚本或命令保存到redis中,然后使用一串sha码调用(可以理解为调用函数)
例子(在redis中执行):
输出:
这里传入的key个数为1,所以redis是key而world是参数
这个操作相当于把脚本加载到redis,得到一个SHA1的校验和,然后使用这个SHA1码来调用对于的Lua脚本,避免每次去发送Lua脚本。
例子:
执行evalsha
如:
redis提供了几个命令来管理脚本
用于将Lua脚本加载到redis内存中
用于判断sha1值是否已经加载到redis内存中
返回个数
用于清除redis内存已经加载的所有脚本
用于杀掉正在执行的Lua脚本
如果Lua脚本比较耗时,甚至Lua脚本存在问题,那么此时Lua脚本的执行会阻塞redis,直到脚本执行完毕或者外部干预将其结束
有一点需要注意,如果Lua脚本正在执行写操作, script kill 命令不会生效,这时只能等待脚本执行结束,或使用 shutdown save 停掉redis服务
可参看 redis官方文档
有两种方式可以调用
这两种方法都可以调用,区别是call()方法是遇到就停止执行后面的内容并直接返回错误,而pcall遇到异常会忽略掉继续执行
其他命令可参看文档这里不赘述
一个使用Lua脚本执行redis scan命令进行批量删除的例子,文件名为 del-batch.lua
调用
执行了之后会删除符合规则 TEST_KEY* 的key
调用结果
Ⅳ 怎么用命令运行lua文本文件
写好脚本script.lua,然后在控制台(cmd)下输入Lua script.lua,
需要Lua后边正确输入你的脚本所在的路径.
Ⅳ lua后缀文件怎么打开以及怎么使用
首先检查自己Window下有没有安装Lua,如果没有的话http://joedf.users.sourceforge.net/luabuilds/去下载你想要的那个版本。
下载下来后无需安装,直接配环境变量。
配在Path下面,打开系统命令执行程序,其实就是cmd。
输入lua,看到版本号之后就证明成功了。
开始执行你的Lua文件,把你的文件准备完毕后。
进入cmd。
输入 lua+空格+你的lua文件名 就可以了,记得要加上lua ,不然window就相当于帮你双击了这个文件而已,Lua就帮你执行输出
Ⅵ 请问LUA用os.execute执行命令时有没有办法不等待执行完毕直接返回啊
没办法。os.execute应该是使用系统的system调用。你说的那种应该是使用类似popen或者其他的方法。除非多线程,否则os.execute肯定阻塞直到调用返回,而tcpmp这种一般要打开管道方便写对方输入,同时读对方输出的。
Ⅶ Windows 下编译 LuaJIT
这里使用 Visual studio 自带的命令行工具来进行编译,所以需要安装好VS。
首先打开VS命令行工具。可以按 Win + S ,输入 prompt 来找到它。如图。
解压 LuaJIT 源码,并进入到解压目录 /src 下。输入 msvcbuild 开始编译。
看到 === Successfully built LuaJIT for xxxxx === 则是编译成功了。
在解压目录 /src 下可以找到编译生成的 luajit.exe 和 lua51.dll .
打开cmd。
如果没有添加环境变量则先定位到LuaJit安装目录。
输入 luajit +文件名 即可运行Lua脚本。
输入 luajit -b +Lua脚本+目标文件名,即可编译脚本。
Ⅷ 请问自己的软件如何运行Lua脚本
programming in lua 有相关的例子,一般脚本语言和c/c++之类的互相调用分两类,一类是扩展,就是将c/c++模块封装起来给脚本语言用,用swig做封装很方便的,一类是嵌入,就是在c/c++等应用中嵌入lua引擎,一般是用来分离经常变化的逻辑部分,比如WOW就是用lua语言作为扩展,用户可以编写lua脚本来完成一些特定功能的机器人。你要做的就是使用lua c api来在你的程序中执行lua。类似这种:
int iErr = 0;
lua_State *lua = lua_open (); // Open Lua
luaopen_io (lua); // Load io library
if ((iErr = luaL_loadfile (lua, "test.lua")) == 0)
{
// Call main...
if ((iErr = lua_pcall (lua, 0, LUA_MULTRET, 0)) == 0)
{
// Push the function name onto the stack
lua_pushstring (lua, "helloWorld");
// Function is located in the Global Table
lua_gettable (lua, LUA_GLOBALSINDEX);
lua_pcall (lua, 0, 0, 0);
}
}
lua_close (lua);
Ⅸ Lua调用uci命令及linux命令
最近项目接触到Openwrt的编译和使用,op本身是一个定制的linux系统,兼容的包和语言也有很多,随着物联网的发展,相信在路由器方面的应用会越来越多,luci作为一个已经在openwrt上集成的web管理工具有很强大的功能,但我的项目里面需要修改和使用自己的配置文件,因此整理一下lua+uci的使用。
Ⅹ Lua常用的文件操作
一、基本的文件读写
(1) io.open
功能:按指定的模式打开一个文件,成功则返回文件句柄,失败则返回nil+错误信息
file = io.open (filename [, mode])
mode 的值有:
r 以只读方式打开文件,该文件必须存在。
w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
r+ 以可读写方式打开文件,该文件必须存在。
w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
a+ 与a类似,但此文件可读可写
b 二进制模式,如果文件是二进制文件,可以加上b
+ 号表示对文件既可以读也可以写
(2) file:write(...)
功能:按指定的参数格式输出文件内容,参数必须为字符或数字,若要输出其它值,则需通过tostring或string.format进行转换
(3) file:close()
功能:关闭文件,我抽U盘才懒得'安全删除硬件',一般都直接拔了.这个命令也一样,反正lua有垃圾自动回收........
(4) io.lines ([filename])
功能:打开指定的文件filename为读模式并返回一个迭代函数,每次调用将获得文件中的一行内容,当到文件尾时,将返回nil,并自动关闭文件
(5) io.popen ([prog [, mode]])
功能:开始程序prog于额外的进程,并返回用于prog的文件句柄(并不支持所有的系统平台)
二、常用文件操作
(1)判断文件是否存在
function checkFileExist(path)
local file = io.open(path, "rb")
if file then file:close() end
return file ~= nil
end
(2)判断文件夹是否存在()
os.execute("cd "..dirPath)
返回值为0便是存在,不为0时表示不存在
(3)创建文件夹
os.execute("mkdir "..dirPath)
(4)删除文件
os.remove(filepath)
eg:创建多层文件夹
Configs.debugFilePath = "E:/test1/test2/test3/test4/test.txt"
function checkDirExist()
local dirlist = string.split(Configs.debugFilePath,"/")
local filenamelen = string.len(dirlist[#dirlist])
local dirpath = string.sub(Configs.debugFilePath,1,string.len(Configs.debugFilePath)-filenamelen-1)
local path_tb={}
local new_path=""
-- 分割路径保存到table
for s in string.gmatch(dirpath,"([^'/']+)") do
if s~=nil then
table.insert(path_tb,s)
end
end
-- 遍历并拼接路径检测是否存在,不存在则新建
for k,v in ipairs(path_tb) do
if k==1 then
new_path=v
else
new_path=new_path.."\\"..v
end
if os.execute("cd "..new_path) ~= 0 then
os.execute("mkdir "..new_path)
end
end
end
(5)获得文件夹下的所有文件路径(windows)
io.popen("dir path /b /s")
eg:
local dirinfo= io.popen("dir path /b /s")
local all = dirinfo:read("*all")