Lua是一门以性能著称的脚本语言,被广泛的应用在很多方面,比如很多游戏的插件。

  很多时候,没有必要去考虑性能的问题,不过,如果我们在开始编写代码的时候就以更适当,性能更高的方式与结构去组织代码,对于程序最后的性能有很大的好处。这不是强调过早的优化代码,只是一种很好的代码编写习惯。


  在Lua中,我们需要知道下面这些:

  使用local

  在代码运行前,Lua会把源码预编译成一种中间码,类似于Java的虚拟机。这种格式然后会通过C的解释器进行解释,整个过程其实就是通过一个while循环,里面有很多的switch...case语句,一个case对应一条指令来解析。

  自Lua 5.0之后,Lua采用了一种类似于寄存器的虚拟机模式。Lua用栈来储存其寄存器。每一个活动的函数,Lua都会其分配一个栈,这个栈用来储存函数里的活动记录。每一个函数的栈都可以储存至多250个寄存器,因为栈的长度是用8个比特表示的。

  有了这么多的寄存器,Lua的预编译器能把所有的local变量储存在其中。这就使得Lua在获取local变量时其效率十分的高。

  来做个试验: 

 a = os.clock()
for i = , do
local x = math.sin(i)
end
b = os.clock()
print(b-a)

  运行时间:

 a = os.clock()
local sin = math.sin
for i = , do
local x = sin(i)
end
b = os.clock()
print(b-a)

  运行时间:

  可见,使用了local效率得到了很大的提升。


  表(table)

  表在Lua中使用十分频繁,因为表几乎代替了Lua的所有容器。所以快速了解一下Lua底层是如何实现表,对我们编写Lua代码是有好处的。

  Lua的表分为两个部分:数组(array)部分和哈希(hash)部分。数组部分包含所有从1到n的整数键,其他的所有键都储存在哈希部分中。

哈希部分其实就是一个哈希表,哈希表本质是一个数组,它利用哈希算法将键转化为数组下标,若下标有冲突(即同一个下标对应了两个不同的键),则它会将冲突的下标上创建一个链表,将不同的键串在这个链表上,这种解决冲突的方法叫做:链地址法。

  当我们把一个新键值赋给表时,若数组和哈希表已经满了,则会触发一个再哈希(rehash)。再哈希的代价是高昂的。首先会在内存中分配一个新的长度的数组,然后将所有记录再全部哈希一遍,将原来的记录转移到新数组中。新哈希表的长度是最接近于所有元素数目的2的乘方。

  从上面可以看出来,表的赋值所需要付出的代价是由表的初始大小与表最后的规模来决定的。

  于是我们可以这么来做:

  如果我们以:

    a = {}

  来创建一个初始表,这个表的大小首先为0,当我们往表中插入数据时,如果表内已经满了,则将触发一次rehash,lua将新创建一个更大的表,直至表再次填满。

  如果在程序运行期间去做这个工作,我们将需要付出更多的时间与性能的代价,于是我们可以这么做:

  如果可以预期表内将有3个元素,则在创建表的时候就填充表的大小,譬如:

    a = {1,1,1}

  这样将使表的填充效率成倍的提升。

  可以做个试验:

 a = os.clock()
for i = , do
local a = {}
a[] =
a[] =
a[] =
end
b = os.clock()
print(b-a)

  以上代码的运行时间为:

  

 a = os.clock()
for i = , do
local a = {,,}
a[] =
a[] =
a[] =
end
b = os.clock()
print(b-a)

  如果创建时便填充了表的大小,结果:

  

  效率提升了差不多1倍。


  关于字符串

  在Lua中,实现字符串类型有一下两个特点:

  第一,所有的字符串在Lua中都只储存一份拷贝。当新字符串出现时,Lua检查是否有其相同的拷贝,若没有则创建它,否则,指向这个拷贝。这可以使得字符串比较和表索引变得相当的快,因为比较字符串只需要检查引用是否一致即可;但是这也降低了创建字符串时的效率,因为Lua需要去查找比较一遍。

  第二,所有的字符串变量,只保存字符串引用,而不保存它的buffer。这使得字符串的赋值变得十分高效。

  在连接字符串时,一般使用的是连接符“..”,不过这个连接方式将会获取连接双方前者的整个拷贝,而如果我们有前者的一个buffer,当连接字符串的时候,只需要在buffer后面直接插入到末尾,这样效率将有很大的提升。于是,在Lua中,可以用table来模仿buffer来处理大字符串连接,可以这么做:

 a = os.clock()
local s = ''
local t = {}
for i = , do
t[#t + ] = 'a'
end
s = table.concat( t, '')
b = os.clock()
print(b-a)

  输出为:

  

  0.05s

  如果不用table,依然用"..": 

 a = os.clock()
local s = ''
for i = , do
s = s .. 'a'
end
b = os.clock()
print(b-a)

  那么时间为:

  

  12.9s,好吧,这个差距确实很大。

  所以,在大字符串连接中,我们应避免使用".."。应用table来模拟buffer,然后concat得到最终字符串。

【Lua】Lua的几点优化原则的更多相关文章

  1. [译] Closures in Lua - Lua中的闭包

    原文:(PDF) . 摘要 一等(first-class)函数是一种非常强大的语言结构,并且是函数式语言的基础特性.少数过程式语言由于其基于栈的实现,也支持一等函数.本文讨论了Lua 5.x用于实现一 ...

  2. [转][译] Closures in Lua - Lua中的闭包

    http://www.cnblogs.com/plodsoft/p/5900270.html?utm_source=tuicool&utm_medium=referral 原文:(PDF) . ...

  3. Oracle SQL 优化原则(实用篇)

    由于SQL优化优化起来比较复杂,并且还受环境限制,在开发过程中,写SQL必须遵循以下几点原则: 1.Oracle 采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他Where ...

  4. oracle优化原则(二)

    SQL优化原则 二.SQL语句编写注意问题 www.2cto.com 下面就某些SQL语句的where子句编写中需要注意的问题作详细介绍.在这些where子句中,即使某些列存在索引,但是由于编写了劣质 ...

  5. 我的mysql数据库sql优化原则

    原文 我的mysql数据库sql优化原则 一.前提 这里的原则 只是针对mysql数据库,其他的数据库 某些是殊途同归,某些还是存在差异.我总结的也是mysql普遍的规则,对于某些特殊情况得特殊对待. ...

  6. js优化原则

    首先,与其他语言不同,JS的效率很大程度是取决于JS engine的效率.除了引擎实现的优劣外,引擎自己也会为一些特殊的代码模式采取一些优化的策略.例如FF.Opera和Safari的JS引擎,都对字 ...

  7. 从字符串拼接看JS优化原则

    来自知乎的问题:JavaScript 怎样高效拼接字符串? 请把以下用于连接字符串的JavaScript代码修改为更高效的方式: var htmlString ='< div class=”co ...

  8. Flex内存泄露解决方法和内存释放优化原则

    Flex内存泄露解决方法和内存释放优化原则 你对Flex内存泄露的概念是否了解,这里和大家分享一下Flex内存释放优化原则和Flex内存泄露解决方法,希望本文的介绍能让你有所收获. Flex内存释放优 ...

  9. ORACLE 数据库优化原则

    ORACLE 数据库优化原则 一.SQL语句用大写的: 因为Oracle总是先解析SQL语句,把小写的字母转换成大写的再厉行. 二.避免在索引列上利用NOT等闲 我们要避免在索引列上利用NOT, NO ...

  10. MySQL 索引优化原则

    一.索引优化原则 1.最左前缀匹配原则,联合索引,mysql会从做向右匹配直到遇到范围查询(>.<.between.like)就停止匹配,比如a = 1 and b = 2 and c & ...

随机推荐

  1. 《Linux企业应用案例精解(第2版)》新书发售啦

    本书在出版当年就获得了不错的销量,同时被中国科学院国家科学图书馆.中国国家图书馆.首都图书馆.清华大学.北京大学等上百所国内综合性大学图书馆收录为馆藏图书,在IT业界赢得了良好的口碑.随后2012年年 ...

  2. 基础篇-struts2的搭建

    .---恢复内容开始--- struts的官网是英文版的,不懂怎么下载的话可以跟着我的步骤来做, 首先去struts的官网http://apache.org/下载struts的报jar类包. 往下拉到 ...

  3. centos 7 挂载大硬盘

    对硬盘sdb进行分区 parted -a optimal /dev/sdb 使用GPT格式 mklabel gpt 建立一个主分区 mkpart primary - 显示分区信息 print 退出 q ...

  4. Android中editText使用报错

    在activity_main.xml文件中添加了editText控件 <EditText        android:id="@+id/edit_text"        ...

  5. 常用MySQL命令整理

    备份数据库 #.备份数据库到sql文件 mysqldump --add-drop-database -h localhost -uusername ppassword dbname > dbna ...

  6. subline text3 删除行 快捷键设置

    打开 首选项-->按键绑定 { "keys": ["ctrl+shift+k"], "command": "run_macr ...

  7. xhprof学习笔记

    一.简介 XHProf 是一个轻量级的分层性能测量分析器. 在数据收集阶段,它跟踪调用次数与测量数据,展示程序动态调用的弧线图. 它在报告.后期处理阶段计算了独占的性能度量,例如运行经过的时间.CPU ...

  8. ExtJs6.0.0随笔

    环境:extJs6.0.0GPL,对应SenchaCmd-6.0.2-windows-64bit(注意版本不能太高). 步骤: 1.安装senchaCmd 2.运行生成demo: http://doc ...

  9. jquery change dropdownlist selected option

    <select name="corporation"> <option value="1">corporation1</optio ...

  10. MyEclipse配置Tomcat 6

    打开首选项 禁用MyEclipse自带的Tomcat 6 下载apache-tomcat-6.0.29.tar.gz 地址:http://yunpan.cn/cKg6kq2RmjdUB  提取码 98 ...