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
为了获取栈缓存的最终内容,只需连接所有的字符串就可以了。
- 点赞
- 收藏
- 分享
- 文章举报
- lua 链表,集合,字符串缓冲
- Lua语法小贴士(四)字符串缓冲
- Lua语言实现:截取给定字符串的部分长度,超出部分用省略号“...”替换
- Lua中语法基本操作(位、字符串、table)
- lua使用table.concat连接大量字符串
- Lua字符串库使用
- Lua里实现将table转成字符串(序列化)和将字符串转换回table(反序列化)
- 【Lua学习笔记】 --> 《字符串string与table的函数操作》
- Lua的字符串分割函数
- 快速掌握Lua 5.3 —— 字符串库 (2)
- Lua 分割字符串
- Lua基础字符串操作
- lua 字符串过滤,特殊字符过滤
- [lua] lua中匹配字符串小数
- Lua学习之从文件中找字符串
- lua字符串对齐函数
- Lua字符串模式匹配函数小结
- lua在字符串中查找是否存在相应的子字符串string.find(s, pattern [, init [, plain]] )
- Lua标准库:表库、字符串库、系统库
- Lua中计算、执行字符串中Lua代码的方法