lua的性能优化

简介: Roberto Ierusalimschy写过经典的Lua 性能提示的文章,链接地址>> 我通过实际的代码来验证,发现一个问题。当我使用 LuaStudio 运行时,发现结果反而与提示相反,甚是奇怪,而使用luac进行运行,与作者给予的提示相符,在某些地方性能可能有优化,比如读取35kb的文件时,时间还是比较快的(可能5.1版本做过优化了)。

Roberto Ierusalimschy写过经典的Lua 性能提示的文章,链接地址>>

我通过实际的代码来验证,发现一个问题。当我使用 LuaStudio 运行时,发现结果反而与提示相反,甚是奇怪,而使用luac进行运行,与作者给予的提示相符,在某些地方性能可能有优化,比如读取35kb的文件时,时间还是比较快的(可能5.1版本做过优化了)。

 

日常的Lua编码中,需要注意以下几点:

1)多使用local

print(_VERSION)

local startTime, endTime


startTime = os.clock()

for i = 1, 100 * 10000 do
    local x = math.sin(i)
end

endTime = os.clock()

print("[local] used time " .. (endTime - startTime) * 1000 .. " ms")



startTime = os.clock()

local sin = math.sin
for i = 1, 100 * 10000 do
    local x = sin(i)
end

endTime = os.clock()

print("[local] used time " .. (endTime - startTime) * 1000 .. " ms")

image

上面二段代码,唯一的区别就是使用 local sin 将 math.sin缓存起来。性能提升约 (107 - 74) / 107 ~= 30.8%,基本符合作者所说的30%的效率提升。

 

startTime = os.clock()
function foo(x)
    for i = 1, 100 * 10000 do
        x = x + math.sin(i)
    end
    return x
end

foo(10)

endTime = os.clock()

print("[foo] used time " .. (endTime - startTime) * 1000 .. " ms")


startTime = os.clock()
function foo2(x)
    local sin = math.sin
    for i = 1, 100 * 10000 do
        x = x + sin(i)
    end
    return x
end

foo2(10)

endTime = os.clock()

print("[foo2] used time " .. (endTime - startTime) * 1000 .. " ms")

image

提升的时间是 (125 – 88) /125 = 29.6%,也约为30%(需要多次测试取平均值)

 

使用闭包,避免动态编译。

startTime = os.clock()
local lim = 10 * 10000
local a = {}
for i = 1, lim do
    a[i] = loadstring(string.format("return %d", i))
end

print(a[10]())

endTime = os.clock()

print("used time " .. (endTime - startTime) * 1000 .. " ms")




startTime = os.clock()
function fk(k)
    return function() return k end
end

local lim = 10 * 10000
local a = {}
for i = 1, lim do
    a[i] = fk(i)
end
endTime = os.clock()

print("used time " .. (endTime - startTime) * 1000 .. " ms")

image

节省了约92%的时间,差异距大。

 

2) 字符串拼接,尽可能使用 table 替代

startTime = os.clock()

local buff = ""
for line in io.lines("C:/Users/zhangyi/Desktop/xxx.txt") do
    buff = buff .. line .. "\n"    
end

endTime = os.clock()

print(collectgarbage("count") * 1024)

print("used time " .. (endTime - startTime) * 1000 .. " ms")




startTime = os.clock()

local buff = ""
local tbl = {}
for line in io.lines("C:/Users/zhangyi/Desktop/xxx.txt") do
    table.insert(tbl, line)
end

buff = table.concat(table, "\n")

endTime = os.clock()

print(collectgarbage("count") * 1024)

print("used time " .. (endTime - startTime) * 1000 .. " ms")

image

差异非常大,无论是内存还是时间,主要原因是:Lua中字符串的拼接都是新创建一个新的字符串,有一个新创建一块内存、copy字符串的动作,时间、空间上消耗都比较大。

 

3) table使用的优化

startTime = os.clock()
for i = 1, 100 * 10000 do
    local a = {}
    a[1] = 1
    a[2] = 2
    a[3] = 3
end
endTime = os.clock()

print("used time " .. (endTime - startTime) * 1000 .. " ms")


startTime = os.clock()
for i = 1, 100 * 10000 do
    local a = {true, true, true}
    a[1] = 1
    a[2] = 2
    a[3] = 3
end
endTime = os.clock()

print("used time " .. (endTime - startTime) * 1000 .. " ms")
image

时间相差一倍,也就是说如果不给{}给定初时化大小,当赋值的时候,它会申请空间来存放相应的值。

 

 

local polyline= {}

for i = 0, 100 * 10000 do
    table.insert(polyline, {x = i, y = 1})
end

print(collectgarbage("count") / 1024)

107.57151889801MB

 

local polyline= {}

for i = 0, 100 * 10000 do
    table.insert(polyline, {i, 1})
end

print(collectgarbage("count") / 1024)

77.053853034973MB

 

local polyline= {
    x = {},
    y = {}
}

for i = 0, 100 * 10000 do
    table.insert(polyline.x, i)
    table.insert(polyline.y, i)
end

print(collectgarbage("count") / 1024)

32.019150733948MB

空间占用差距也非常大,从上面似乎可以得到这样的结论:尽可能减少table的长度,尽可能使用array 而不是 hash。

 

综上所述,尽可能多使用local,减少查询的性能损耗。json数据表如果需要转化为table时,改变数据的存储结构可能减少很大的内存使用。

目录
相关文章
|
人工智能 算法 程序员
|
人工智能 索引
Lua性能优化指南
本文主要取材于Lua Programming Gems一书的第二章Lua Performance Tips,总结了Lua性能优化的几个基本要点,并对每个点给出了具体的测试代码和时间性能对比数据。
3311 0
|
3月前
|
存储 NoSQL Redis
Redis的Lua脚本有什么作用?
Redis Lua脚本用于减少网络开销、实现原子操作及扩展指令集。它能合并操作降低网络延迟,保证原子性,替代不支持回滚的事务。通过脚本,代码复用率提高,且可自定义指令,如实现分布式锁,增强Redis功能和灵活性。
129 1
|
2月前
|
消息中间件 NoSQL Java
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
158 0
|
4天前
|
存储 NoSQL Redis
Tair的发展问题之在Redis集群模式下,Lua脚本操作key面临什么问题,如何解决
Tair的发展问题之在Redis集群模式下,Lua脚本操作key面临什么问题,如何解决
|
3月前
|
缓存 NoSQL Java
【Redis】5、Redis 的分布式锁、Lua 脚本保证 Redis 命令的原子性
【Redis】5、Redis 的分布式锁、Lua 脚本保证 Redis 命令的原子性
131 0
|
2月前
|
JSON 监控 数据格式
使用Lua代码扩展上网行为管理软件的脚本功能
本文介绍了如何使用Lua脚本增强上网行为管理,包括过滤URL、记录用户访问日志、控制带宽和自动提交监控数据到网站。Lua是一种轻量级语言,适合编写扩展脚本。文中提供多个示例代码,如URL过滤器、用户活动日志记录器和带宽控制器,帮助用户根据需求定制网络管理功能。通过这些示例,用户可以快速掌握Lua在上网行为管理中的应用。
125 4
|
2月前
|
NoSQL API Redis
使用Redis Lua脚本实现高级限流策略
使用Redis Lua脚本实现高级限流策略
96 0
|
2月前
|
消息中间件 NoSQL Java
Spring Boot中使用Redis和Lua脚本实现延时队列
Spring Boot中使用Redis和Lua脚本实现延时队列
|
3月前
|
算法 NoSQL Java
springboot整合redis及lua脚本实现接口限流
springboot整合redis及lua脚本实现接口限流
186 0