您的位置:首页 > 编程语言 > Lua

Lua—字符串缓冲

2020-03-08 11:23 836 查看

字符串缓存

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

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

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

  • 点赞
  • 收藏
  • 分享
  • 文章举报
甜甛恬栝湉铦i 发布了13 篇原创文章 · 获赞 0 · 访问量 175 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: