翻译自《Lua Programming Gems》Chapter 2:Lua Performance Tips:Basic fact By Roberto Ierusalimschy
编写高效Lua代码的方法
字符串
和表一样,了解Lua如何实现字符串(string)对高效地使用字符串是有好处的。
Lua实现字符串的方式有两个地方跟其它脚本语言截然不同。首先,Lua中的所有字符串都被内部化;这意味着Lua中所有的字符串只有一份拷贝。任何时候,当一个新的字符串出现时,Lua会先检查这个字符串是否已经有一份拷贝,如果有,就重用这份拷贝。内部化使字符串比较和表索引等操作变得非常快,但是字符串的创建会变慢。
第二,Lua中的字符串变量不包含字符串实体,而是一个字符串的引用。这种实现加快了若干字符串操作。比如说,在Perl里,如果你写下类似这样的语句:$x= $y,$y包含一个字符串,这个赋值语句将复制$y缓冲区字符串的内容到$x的缓冲区中。如果这个字符串很长,这个操作将是非常昂贵的。在Lua里,执行这条赋值语句只是复制了一个指向实际字符串的指针。
这种使用引用来实现字符串的方案,降低了某种方式的字符串连接的速度。在Perl里,操作$s= $s . "x"和$s .= "x"是很不同的。前一个语句,你得到的是一份$s的拷贝,这份拷贝后面加入了"x"。后一个语句,"x"只是被简单地放在了$s的缓冲区之后。所以第二种连接格式跟字符串的大小是无关的(假设缓冲区有足够的空间来存放连接的字符)。如果你将这两条语句放在一个循环中,那么它们的区别相当于一个线性复杂度的算法和一个平方复杂度的算法。比如,一下循环用了五分钟时间来读取一个5MB的文件:
$x = "";
while (<>) {
$x = $x . $_;
}
如果我们将$x = $x . $_替换成$x .= $_,以上片段只耗费0.1秒的时间!
Lua并没有提供第二种,也就是比较快的方法,因为Lua的字符串变量并不拥有缓冲区,所以我们必须显式地使用一个缓冲区:包含了字符串碎片的表来完成这项工作。下面的代码耗费了0.28秒来读那个5MB的文件。不比Perl快,不过很不错了。
local t = {}
for line in io.lines() do
t[#t + 1] = line
end
s = table.concat(t,"\n")