当前位置: 首页 > news >正文

Lua使用总结

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

lua+redis

Lua 环境安装

Linux环境安装

选择你需要的Lua版本:http://www.lua.org/ftp/

curl -R -O http://www.lua.org/ftp/lua-5.3.4.tar.gz
tar zxf lua-5.3.4.tar.gz
cd lua-5.3.4
make linux test
make install

测试安装环境错误:

cd src && make linux
make[1]: Entering directory `/home/webapps/lua/lua-5.3.4/src'
make all SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline"
make[2]: Entering directory `/home/webapps/lua/lua-5.3.4/src'
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX    -c -o lua.o lua.c
lua.c:82:31: 错误:readline/readline.h:没有那个文件或目录
lua.c:83:30: 错误:readline/history.h:没有那个文件或目录
lua.c: 在函数‘pushline’中:
lua.c:312: 警告:隐式声明函数‘readline’
lua.c:312: 警告:赋值时将整数赋给指针,未作类型转换
lua.c: 在函数‘addreturn’中:
lua.c:339: 警告:隐式声明函数‘add_history’
make[2]: *** [lua.o] 错误 1
make[2]: Leaving directory `/home/webapps/lua/lua-5.3.4/src'
make[1]: *** [linux] 错误 2
make[1]: Leaving directory `/home/webapps/lua/lua-5.3.4/src'
make: *** [linux] 错误 2

解决方案:

yum install libtermcap-devel ncurses-devel libevent-devel readline-devel

安装成功:

lua -v
Lua 5.3.4  Copyright (C) 1994-2017 Lua.org, PUC-Rio

编写测试代码:

vi lua_coding.lua --新建文件

print("Hello World Keep Coding!!!") --执行代码

lua lua_coding.lua --执行

Windows 环境安装

Window 系统上安装 Lua window下你可以使用一个叫"SciTE"的IDE环境来执行lua程序,下载地址为:

  • 本站下载地址:LuaForWindows_v5.1.4-46.exe
  • Github 下载地址:https://github.com/rjpcomputing/luaforwindows/releases
  • Google Code下载地址 : https://code.google.com/p/luaforwindows/downloads/list 双击安装后即可在该环境下编写 Lua 程序并运行。

你也可以使用 Lua 官方推荐的方法使用 LuaDist:http://luadist.org/

国人开发IDEA Lua插件:https://github.com/tangzx/IntelliJ-EmmyLua

Lua语法

以下代码保存文件可以直接运行: 新建2个模块测试文件:TestMod.lua, TestLoad.lua

TestMod.lua 代码

local TestMod = {}

local function getname()
    return "无忌"
end

function TestMod.Greeting()
    print("Hello, My name is "..getname())
end

return TestMod

TestLoad.lua 代码

print('load...')

测试代码:

print("Hello World Keep Coding!!!")

--注释
--[[

多行注释

--]]


--[[
变量

NULL在Lua中是nil
lua中的变量如果没有特殊说明,全是全局变量,那怕是语句块或是函数里。变量前加local关键字的是局部变量

--]]


theGlobalVar = 50  --全局变量
local theLocalVar = "local variable" --本地变量

-- 5种方式定义的变量,字符串相等
a1 = 'alo\n123"'
a2 = "alo\n123\""
a3 = '\97lo\10\04923"'
a4 = [[alo
123"]]    -- 多行变量定义的方式
a5 = [===[
alo
123"]===]  -- [=[之间多少个==都没关系

nullvar = null

print('---- 变量 ----')
print(a1 == a2)
print(a2 == a3)
print(a3 == a4)
print(a4 == a5)
print('nullvar == nil is',nullvar == nil)
print('---- 变量 ----')


print('---- 控制语句 ----')
print('---- if-else分支 ----')

io.write('请输入年龄:')
local age = io.read("*number")
io.read() -- 回车符
io.write('请输入性别(男|女):')
local sex = io.read()

if age == 40 and sex =="男" then
    print("男人四十一枝花")
elseif age > 60 and sex ~="女" then
    print("old man without country!")
elseif age < 20 then
    io.write("too young, too naive!\n")
else
    print("Your age is "..age)
end

print('----  for循环 ----')
sum = 0
for i = 100, 1, -2 do
    sum = sum + i
end
print("sum =",sum)


print('----  while循环 ----')
-- Lua没有++或是+=这样的操作
sum = 0
num = 1
while num <= 100 do
    sum = sum + num
    num = num + 1
end
print("sum =",sum)

print('----  until循环 ----')
sum = 2
repeat
   sum = sum ^ 2 --幂操作
   print('until循环 sum=',sum)
until sum > 1000

print('---- 控制语句 ----')

print('\n---- 函数 与JavaScript 写法类似 ----')

print('---- 递归 ----')
function fib(n)
  if n < 2 then return 1 end
  return fib(n - 2) + fib(n - 1)
end

print(fib(2))


print('---- 闭包 ----')

function newCounter()
    local i = 0
    return function()     -- anonymous function
       i = i + 1
        return i
    end
end

c1 = newCounter()
print(c1())  --> 1
print(c1())  --> 2


function myPower(x)
    return function(y) return y^x end
end

power2 = myPower(2)
power3 = myPower(3)

print('4的2次方=',power2(4)) --4的2次方
print('5的3次方=',power3(5)) --5的3次方

--函数的返回值,可以一次返回多个值

function returnMultiParam()
	return '无忌', 'nassir.wen@gmail.com', 40
end
print('方法返回多个参数:',returnMultiParam())

--局部函数 JavaScript类似

function foo(x) return x^2 end
foo = function(x) return x^2 end


print('---- Table对象(支持Array 和 Map结构) ----')
--所谓Table其实就是一个Key Value的数据结构,它很像Javascript中的Object,或是PHP中的数组,在别的语言里叫Dict或Map

arr = {name='无忌',age=37,email='nassir.wen@gmail.com'}
arr2 = {10,20,30} -- 等价于  {[1]=10,[2]=20,[3]=30}
arr3 = {'无忌',function(x) return x + 1 end} -- 数组中可以定义不同类型,也可以定义方

-- 遍历数组
for k, v in pairs(arr) do
    print(k, v)
end

for i = 1, #arr2 do -- 数组下标从0开始, #arr2代表arr2长度
	print(arr2[i])
end

print('调用数组中的方法:',arr3[2](1))

print('---- MetaTable 和 MetaMethod ----')
-- MetaTable和MetaMethod是Lua中的重要的语法,MetaTable主要是用来做一些类似于C++重载操作符式的功能

fraction_a = {numerator=2, denominator=3}  --分数 2/3
fraction_b = {numerator=4, denominator=7}  --分数 4/7

-- 如果直接执行 fraction_a + fraction_b 会报错,我们需要通过MetaTable处理

-- 使用MetaTable
fraction_op={}
function fraction_op.__add(f1, f2)
    ret = {}
    ret.numerator = f1.numerator * f2.denominator + f2.numerator * f1.denominator
    ret.denominator = f1.denominator * f2.denominator
    return ret
end

-- 为之前定义的两个table设置MetaTable:(其中的setmetatble是库函数)
setmetatable(fraction_a, fraction_op)
setmetatable(fraction_b, fraction_op)

fraction_s = fraction_a + fraction_b

print('MateTable 实现分数对象相加:', fraction_s.numerator, '/' , fraction_s.denominator)

print('---- 面向对象(有点像Javascript的prototype)----')
--[[ 面向对象的实现,主要是使用MetaMethod的__index重载,所谓__index,说得明确一点,如果我们有两个对象a和b,我们想让b作为a的prototype只需要
setmetatable(a, {__index = b})
--]]

Person={}

function Person:new(p)
    local obj = p
    if (obj == nil) then
        obj = {name="无忌", age=18, handsome=true}
    end
    self.__index = self
    return setmetatable(obj, self)
end

function Person:toString()
    return self.name .." : ".. self.age .." : ".. (self.handsome and "handsome" or "ugly")
end

--[[
1)self 就是 Person,Person:new(p),相当于Person.new(self, p)
2)new方法的self.__index = self 的意图是怕self被扩展后改写,所以,让其保持原样
3)setmetatable这个函数返回的是第一个参数的值。
--]]

-- 测试
me = Person:new()
print(me:toString())

kf = Person:new{name="King's fucking", age=70, handsome=false}
print(kf:toString())


-- 继承,同样使用setmetatable

Student = Person:new()

function Student:new()
    newObj = {year = 2013}
    self.__index = self
    return setmetatable(newObj, self)
end

function Student:toString()
    return "Student : ".. self.year.." : " .. self.name
end

stu = Student:new{name='无忌'}

print('Student 继承:',stu:toString())


print('---- 模块 ---- ')
--[[
加载文件几种方式区别:
require("model_name") 载入相同文件只会执行一次
dofile("model_name") 载入相同文件每次都会执行
loadfile("model_name") 载入文件不执行,等你需要执行的时候再执行

3种方式测试: 文件 TestLoad.lua

print('load...')

--]]

print('---- 测试require加载3次 ----')
require('testload')
require('testload')
require('testload')
print('---- 测试require加载3次 ----')

print('---- 测试dofile加载3次 ----')
dofile('testload.lua')
dofile('TestLoad.lua')
dofile('TestLoad.lua')
print('---- 测试dofile加载3次 ----')

print('---- 测试loadfile加载3次 ----')
loadfile('testload')
loadfile('testload')
loadfile('testload')
print('---- 测试loadfile加载3次 ----')

-- 具体模块实现
--[[
 模块名: TestMod.lua

local TestMod = {}

local function getname()
    return "无忌"
end

function TestMod.Greeting()
    print("Hello, My name is "..getname())
end

return TestMod

--]]

-- 调用
local test_mod = require("TestMod")
test_mod.Greeting()


Lua + Redis集群 秒杀场景使用

实现逻辑:

  • 秒杀商品先保存在Redis
  • 确认下单资格,通过Lua脚本扣减库存,由于Redis是单线程模型,Lua可以保证多个命令原子性

初始化商品数据:

模拟数据格式:goodsId 商品ID,Total 商品总数,Booked 商品已预定数
"goodsId" : {
    "Total": 3
    "Booked": 0
}

执行redis初始化:

 redis 127.0.0.1:6379> HMSET goodsId Total 3 Booked 0
 OK
 redis 127.0.0.1:6379> HMGET goodsId Total Booked
 1) "3"
 2) "3"

Lua实现扣减库存脚本: seckill.lua

local n = tonumber(ARGV[1])
if not n  or n == 0 then
    return 0       
end                
local vals = redis.call('HMGET', KEYS[1], 'Total', 'Booked');
local total = tonumber(vals[1])
local blocked = tonumber(vals[2])
if not total or not blocked then
    return 0       
end                
if blocked + n <= total then
    redis.call('HINCRBY', KEYS[1], 'Booked', n)                                  
    return n;   
end                
return 0

将扣减库存脚本加载到Redis:

./redis-cli SCRIPT LOAD "$(cat /usr/local/redis/bin/seckill.lua)"
59dac41ffd27bef73ae87593da59b783b737a04b

执行扣减代码:

 127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1
(integer) 1
127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1
(integer) 1
127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1
(integer) 1
127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1
(integer) 0
127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1
(integer) 0
127.0.0.1:6379> EVALSHA 59dac41ffd27bef73ae87593da59b783b737a04b 1 goodsId 1

返回 1 扣减成功
返回 0 扣减失败

执行函数说明

EVAL script numkeys key [key ...] arg [arg ...]
EVAL 执行脚本 key数量 key值 执行参数
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
EVALSHA 执行sha1效验值 key数量 key值 执行参数

每个被执行过的 Lua 脚本, 在 Lua 环境中都有一个和它相对应的函数, 函数的名字由 f_ 前缀加上 40 个字符长的 SHA1 校验和构成: 比如 f_5332031c6b470dc5a0dd9b4bf2030dea6d65de91 。

只要脚本所对应的函数曾经在 Lua 里面定义过, 那么即使用户不知道脚本的内容本身, 也可以直接通过脚本的 SHA1 校验和来调用脚本所对应的函数, 从而达到执行脚本的目的 —— 这就是 EVALSHA 命令的实现原理。

参考

Lua环境搭建:http://www.runoob.com/lua/lua-environment.html
Lua简明教程(入厕文章):https://coolshell.cn/articles/10739.html
Aliyun redis集群: https://help.aliyun.com/document_detail/63920.html?spm=a2c4g.11186623.6.611.A4j6rw
Redis中Lua脚本使用: http://redisbook.readthedocs.io/en/latest/feature/scripting.html

转载于:https://my.oschina.net/wenjinglian/blog/1823554

相关文章:

  • Python模块-threading模块
  • xtrabackup 备份原理
  • tkinter简单打开网址 + 执行系统命令
  • flask学习笔记之flask-migrate
  • 项目实战 (规范、轮子、学习案例) - iOS
  • iOS中类、元类、isa详解
  • 生鲜 B2B 平台的产品体系如何迭代(B2B 技术共享第三篇)
  • CentOS7.X安装php-7.x.x
  • 2018年UI设计师的前景如何?长沙牵引力用数据告诉你
  • JS深拷贝总结
  • centos7安装
  • 万万没想到,枯燥的“机器学习”还可以这样学!
  • 被忽略的对象
  • Xtrabackup 使用stream输出并压缩备份
  • 一个UPDATE语句引发的血案
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • CSS实用技巧干货
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • EOS是什么
  • Flex布局到底解决了什么问题
  • Go 语言编译器的 //go: 详解
  • golang中接口赋值与方法集
  • java取消线程实例
  • leetcode388. Longest Absolute File Path
  • MySQL数据库运维之数据恢复
  • 从伪并行的 Python 多线程说起
  • 复习Javascript专题(四):js中的深浅拷贝
  • 关于for循环的简单归纳
  • 记一次和乔布斯合作最难忘的经历
  • 记一次用 NodeJs 实现模拟登录的思路
  • 深入 Nginx 之配置篇
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 通过git安装npm私有模块
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ###STL(标准模板库)
  • $L^p$ 调和函数恒为零
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (6)添加vue-cookie
  • (C语言)strcpy与strcpy详解,与模拟实现
  • (C语言)逆序输出字符串
  • (Java数据结构)ArrayList
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (六)vue-router+UI组件库
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (南京观海微电子)——COF介绍
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (原創) 未来三学期想要修的课 (日記)
  • (转)【Hibernate总结系列】使用举例
  • (转)Mysql的优化设置
  • ..回顾17,展望18
  • .NET 设计一套高性能的弱事件机制