Lua—字符串缓冲

字符串缓存

正常我们读取文件时,会写这样一段代码:

local buff = ""
for line in io.lines() do
buff = buff..line..'\n'
end

这段代码,看着可以正常工作,但是面对较大的文件时,工作效率就极低,且会导致巨大的性能开销。
例如,用这段代码读入350KB的文件数据,就需要将近1分钟的时间。
我们来搞清楚运行这段代码的时候,具体做了哪些流程。

假设我们现在在读取的环节,假设每一行20个字节,已经读入2500行,那么现在buff就是一个50KB的字符串。而当Lua作为字符串连接buff…line时就会创建一个长为50020字节的新字符串,并从buff中复制了50000字节到新的字符串,这样对于后面的每一行数据,Lua都需要移动50KB或者更多的内存。在读取100行(大于2KB)的数据,Lua已经移动了5MB的内存,而且我们的代码具有2次复杂度,最后读取完350KB的数据,Lua则会移动50GB的数据,想想就恐怖。

所以在Lua中读取大量文件时,提供了一个io.read("*all")选项。
另外还有一种方法,用table作为一个缓冲区,用到一个关键函数 table.concat
这个函数什么作用呢? 首先它会将给定列表的所以字符串连接起来,并且返回连接的结果。用concat重写上面的代码如下:

local t= {}
for line in io.lines() do
    t[#t+1]=line	
end
t[#t+1] = ""
table.concat(t,"\n")

从内部来看,concat和io.read("*all")都使用了同一个算法拼接小的字符串,我们来分析它是如何工作的。
开始时,使用的是线性的方法来连接字符串,把较小的字符串逐个连接起来,最后将连接的结果存入到一个累加器中。而新的算法避免这么做,他采用二分的方法,从某种情况下将小的字符串拼接起来
,然后再将结果字符串与更大的字符串拼接起来。其算法核心是一个栈,已创建的大字符串位于栈的底部,而较小的字符串则通过栈顶进入。对栈中元素处理的方式很像“汉诺塔”的问题,栈中的任意字符串都比下面的字符串短。如果新加入的字符串比下面已存在的字符串长,则把两者连接起来。然后,再将连接后的新字符串与更下面的字符串作比较,如果新建的字符串更长的话,则再次连接他们。这样一直向下延续应用,直到遇到更大的字符串或者到达栈底停止。

function addString(stack ,s)
  stack[#stack+1] = s      --将s压入栈中
  for #stack-1,1,-1 do
     if #stack[i] > #stack[i+1] then
        break
     end
     stack[i] = stack[i]..stack[i+1]
     stack[i+1]=nil
  end       

为了获取栈缓存的最终内容,只需连接所有的字符串就可以了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值