编写高效Lua代码的方法 - 2 - 表相关

编写高效Lua代码的方法 - 总结 基础 1 尽量使用local       使用变量的效率:local > upvalue > global       local变量存放在栈中,upvalue存放在链表中,global变量存放在全局的表中。       例子:  使用local function Add() local x, y return x + y end  使用upvalue 阅读详情

翻译自《Lua Programming Gems》Chapter 2:Lua Performance Tips:Basic fact By Roberto Ierusalimschy

编写高效Lua代码的方法

表相关

通常情况下,你在使用表(table)的时候并不需要任何有关Lua如何实现表的细节。事实上,Lua竭尽全力地避免实现细节暴露给用户。但是这些细节还是在table操作的性能中暴露出来了。所以,为了高效地使用表,知道一点Lua如何实现table是有好处的。

    Lua使用了一些巧妙的算法来实现table。每个表包含两部分:数组(array)部分和哈希(hash)部分,数组部分保存整数键值(key)为1到n范围内的值(entry),n是一些独特的数值。(我们后面会讨论在某一刻n是怎么被计算出来的。)其他的值(包括整数下标超出1到n范围的)保存在哈希部分。

    顾名思义,哈希部分使用哈希算法来保存和查找里面的键值。它使用的是开发地址列表,所有的值都存在哈希数组里。哈希函数算出一个键值的主索引;如果发生碰撞(两个键值的哈希值是相同的),这些有相同主索引的键值将会被连成一个链表,每个元素在数组中占一个位置。

    当Lua需要在表中插入一个新的键值而此时哈希数组没有空位置时,Lua将会做一次重新哈希(rehash)。重新哈希的第一步是决定新的数组部分和哈希部分的大小。所以Lua会遍历表中的所有值,对这些值进行计数和分类,然后选择一个小于数组部分大小的2的最大指数值,使数组的一半以上会被使用。哈希部分的大小就是大于剩下的值(不能放在数组部分的值)的数量的最小2的指数值。

    当Lua创建一个空表的时候,其中的两部分的大小都是0,并且此时并没有赋予他们内存空间。下面我们来看看下面代码会发生什么事情:

local a = {}
for i = 1, 3 do
    a[i] =true
end

代码一开始创建一个空表。第一次循环的时候,赋值语句a[1]=true触发了一次重新哈希计算;Lua将表中的数组部分大小设为1,哈希部分还是空的。第二次循环的时候,赋值语句a[2]=true又触发了一次重新哈希计算,现在,表中的数组部分大小为2。最后,第三次循环又触发了一次重新哈希计算,数组部分的大小增大到4。

代码:

a = {}
a.x = 1; a.y = 2; a.z = 3

做的事情是类似的,不过大小增长的是table中的哈希部分。

    对于大型的表,这些初始化开销将会被整个创建过程平摊:一个包含三个元素的表需要进行3次重新哈希计算,而一个包含了一百万个元素的表只需要20次。但是当你创建几千个小的表时,总开销就会很显著。

    老版本的Lua在创建空表的时候会为其预分配一些空位(如果没记错,是4),来避免创建较小的表时的开销。但是这样可能会出现浪费内存的情况。比如,如果你创建几百万个点(在表里面只存放了两个数字),那么每个点使用的内存将会是其真正需要的内存的两倍,你将会付出高昂的代价。这就是为什么现在的Lua没有为空表预分配空位。

    如果你是用C语言编程,你可以通过调用Lua的API函数lua_createtable来避免这些重新哈希计算。它在随处可见的lua_State中获取两个参数:新表数组部分的初始大小和哈希部分的初始大小。通过提供一个适当的初始大小给新表,可以很容易地避免这些初始化时的重新哈希计算。需要注意的是,Lua只有在进行重新哈希计算的时候,才会缩小表的大小。所以,如果你提供的初始大小比实际使用的大的话,Lua不会纠正你对空间的浪费。

    当你在Lua下面编程的时候,你可以通过构造来避免那些初始化的重新哈希计算。当你写下{true,true, true}的时候,Lua就会事先知道新的表的数组部分将会用到3个空位,并创建一个相应大小的表。类似的,当你写下{x = 1, y = 2, z =3}的时候,Lua将创建一个哈希部分包含4个空位的表。作为例子,下面的循环将会运行2.0秒:

for i = 1, 1000000 do
    local a= {}
    a[1] =1; a[2] = 2; a[3] = 3
end
如果以一个适当的初始大小来创建一个表的话,运行时间将会降低到0.7秒:
for i = 1, 1000000 do
    local a ={true, true, true}
    a[1] = 1;a[2] = 2; a[3] = 3
end

但是,当你写下类似{[1] = true, [2] = true, [3] =true}的时候,Lua并没有聪明到检测到以上的表达式(这里指字面数字123)是在描述数组下标,所以它创建了一个哈希部分有四个空位的表,这浪费了内存和CPU时间。

    表的两个组成部分的大小只在表进行重新哈希计算的时候计算出来,而重新哈希计算只会在表已经被放满时需要插入一个新元素的时候发生。因此,当你遍历一个表并把其中的元素都删除的时候(就是把表里的值设为nil),表并不会缩小。当你插入一些新元素时,表才会重新改变其大小。通常这并不是一个问题:当你持续地删除和插入元素时(很多程序的典型情况),表的大小将保持稳定。你不应该通过在一个巨大的表中删除一些数据来节省空间:删除这个巨大的表会更好。

    有一种比较肮脏的手段来强迫表进行重新哈希计算,就是通过在表中插入足够的nil元素。看看以下例子:

a = {}
lim = 10000000
for i = 1, lim do a[i] = i end -- 创建一个巨大的表
print(collectgarbage("count")) -->196626
for i = 1, lim do a[i] = nil end -- 删除其所有的元素
print(collectgarbage("count")) -->196626
for i = lim + 1, 2*lim do a[i] = nil end -- 插入大量nil元素
print(collectgarbage("count")) --> 17

除了个别特殊情况之外,我不推荐这种手法,因为这样很慢,并且没有比较简单的方法来获知“足够”到底是多少。

    你可能会好奇为什么我们插入nil元素时Lua没有缩小表的大小。首先,是为了避免需要测试我们正插入什么东西到表中;测试插入的元素是否为nil会降低所有赋值语句的速度。第二个原因,更重要的是,为了允许遍历表时,对表元素赋nil值。考虑一下循环:

for k, v in pairs(t) do
    ifsome_property(v) then
        t[k]= nil -- 删除这个元素
    end
end

如果Lua在表元素被赋nil值之后进行重新哈希,将会摧毁这个遍历。

    如果你想删除表中的所有元素,下面一个简单的循环式其中一种正确的方法:

for k in pairs(t) do
    t[k] = nil
end
另外一个“智能”的选择是下面的这个循环:
while true do
    local k =next(t)
    if not kthen break end
    t[k] = nil
end
     然而,这个循环再表很大的时候会很慢。当调用函数next时,如果没有传入前一个键值作为参数,函数next会返回表中的“第一个”元素(以一种随机的排序方法)。为了做到这个,next函数会从表的数组部分的开头开始遍历,查找非nil元素。随着循环将一个个的第一个元素设为nil,查找第一个非nil元素变得越来越久。最后,这个“智能”循环用了20秒时间来清除一个有100000元素的表;使用pairs的遍历表的循环则耗费了0.04秒。 
Lua中的元表和元方法 元表可以修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定操作。 元方法会检测一个操作中的值是否有元表,以及元表是否定义了操作的元方法。如两个table相加,先检查两者之一是否有元表,之后检查是否有一个叫“__add”的字段,若找到,则调用对应的值。“__add”等字段,其对应的值(一般是一个函数或是table)就是“元方法”。 阅读详情

相关推荐

Learning Lua Programming (3) iMac下搭建Lua脚本最好的编码环境(代码补全,编译运行)

这篇文章记录一下如何在MAC系统环境下,搭建LUA脚本最好的编码环境,具有强大的代码补全,而且可以编译运行。 这里使用到的还是sublime text编辑器。下面开始进行详细的介绍: (1)下载sublime text 注意版本号为2.0.2,下载地址:sublime text 2下载地址  (2)安装lua环境 进入这个页面进行lua安装 点击打开链接 ,在这个页面中,提示到有

小邓笔记 4487

编写高效Lua代码的方法

翻译自《Lua Programming Gems》Chapter 2:Lua Performance Tips:Basic fact By Roberto Ierusalimschy 基本知识 Lua在运行代码之前,会先把源码翻译(预编译)成一种内部编码,这种编码由一连串的虚拟机能够识别指令构成,与CPU的机器码很相似。接下来由C代码中的一个while循环负责解释这些内部编码,

1048

Lua游戏开发(一)---Lua语言

介绍 Lua的设计和实现目标:提供一种嵌入式的脚本编程语言,简洁、高效、可移植并且是轻量级的。 传统上大部分虚拟机都是基于堆栈的,自Pascal的P-虚拟机开始一直到今天的Java虚拟机以及Microsoft.Net。Lua5.0的虚拟机是基于寄存器的虚拟机,Perl6(Parrot)也是。 简洁:寻求最简化的语言和最小化的源码(以C语言实现)。这也意味着Lua只有一些类似传统编程语言的

xiaocai_36 8491

lua代码格式化_Lua中的元表与元方法

前言Lua中每个值都可具有元表。元表是普通的Lua表,定义了原始值在某些特定操作下的行为。你可通过在值的原表中设置特定的字段来改变作用于该值的操作的某些行为特征。例如,当数字值作为加法的操作数时,Lua检查其元表中的"__add"字段是否有个函数。如果有,Lua调用它执行加法。我们称元表中的键为事件(event),称值为元方法(metamethod)。前述例子中的事件是"add",元方法...

weixin_39891262的博客 467

skynet 热更新 lua 代码

skynet是为多人在线游戏设计的轻量级服务端框架,使用C+Lua开发。skynet的特点是,使用这个框架,太多数情况下只是用lua写代码,很少用c写,这一定程度上提高了项目的开发效率。lua虽然没有C高效,但开发复杂业务却是非常便捷。不过,skynet网上文档很少,所以我就利用一点时间总结skynet相关内容。文章介绍skynet热更新lua代码及各自特点

没有开花的树 8147

XLua代码提示全攻略:如何在VSCode中高效开发Unity Lua脚本

本文详细介绍了如何在VSCode中为XLua配置高效的代码提示环境,提升Unity Lua脚本开发效率。从基础工具安装到高级类型提示优化,涵盖VSCode插件配置、XLua API设置、代码片段定制等实用技巧,帮助开发者快速搭建专业的Lua开发工作流。

weixin_30687051的博客 209

Lua 第5部分 表

表( Table )是 Lua 语言中最主要(事实上也是唯一的)和强大的数据结构。使用表,Lua语言可以以一种简单、统一且高效的方式表示数组、集合、记录和其他很多数据结构。Lua语言也使用表来表示包( package )和其他对象。当调用函数 math.sin 时 ,我们可能认为是“调用了 math 库中函数 sin ”;而对于 Lua 语言来说,其实际含义是“以字符串sin ” 为键检索表 math ”。

u012616827的博客 1315

全面掌握Lua脚本开发工具实战指南

Lua是一种轻量级的脚本语言,最初设计用于嵌入到应用程序中提供灵活的扩展和定制功能。它以其简单性、可移植性以及强大的功能组合而受到开发者的青睐。本章将带你了解Lua的基本概念、语言特点以及它在现代软件开发中的应用。Lua支持常见的控制结构,如if-then-else、for、while等。函数是Lua中的一级值,可以像任何其他值一样被传递。例如:endelseend在Lua中,函数体由关键字function开始,end结束。可以定义无参数的函数,也可以通过...

weixin_42400643的博客 1025

Lua元表

在开始介绍元表之前,我们先大致了解Lua是什么。Lua 是一种可嵌入、轻量、快速、功能强大的脚本语言。Lua 很适合用于配置、脚本化、插件化和快速构造原型的场景。Lua 是一门轻量级脚本语言,其核心设计目标之一是简单而高效。Lua 体积小、启动速度快,在所有脚本引擎中,Lua 的速可以于说是最快的。Lua 运行依托于宿主语言可以是c++,c#,golang等,只需要实现Lua解释器。

nanyupeng的博客 976

iTunes备份文件路径修改方法

因为以前的很多帖子iTunes都不是从微软下载的,而现在的iTunes一般都是微软商店里面的,它的路径为:“C:\Users\ 你的用户名 \Apple\MobileSync” (注:用户名,根据个人电脑名称更改)打开iTunes备份路径:“C:\Users\txh\AppData\Roaming\Apple Computer\MobileSync”,其中文件夹MobileSync就是用来存放备份文件的。创建你想备份纯在的目录创建备份文件目录(我的是G:/APPLE/Backup)2.粘贴的剪切文件目录。

尘玥的故事 1万+

从SD更新字库到FLASH,再用LCD显示

用Flash当字库存储载体。思路是先将要用到的字库文件存在SD卡,然后存储到Flash,LCD显示时候从Flash中读取 还挺顺利的,移植的原子的程序,自己稍加修改,主要是我的液晶屏函数,Flash读写函数,还有存储文件的flash地址不一样。一晚上搞定,大小字体都OK。挺高兴哈哈。这几天忙工作事情有点耽搁了学习进展嘿嘿 在text.c的showstr函数中char的字体颜色随意设置的,可以显...

weixin_30505751的博客 914

LUA教程表相关的Metamethods 只读表 -58

采用代理的思想很容易实现一个只读表。我们需要做得只是当我们监控到企图修改表时候抛出错误。通过__index metamethod,我们可以不使用函数而是用原始表本身来使用表,因为我们不需要监控查寻。这是比较简单并且高效的重定向所有查询到原始表的方法。但是,这种用法要求每一个只读代理有一个单独的新的metatable,使用__index指向原始表: function readOnly (t) local proxy = {} local mt = { -- create .

511遇见 1513

不止于修改器:用Cheat Engine(CE)的Lua脚本和D3D Hook打造你的游戏辅助界面

本文深入探讨了Cheat Engine(CE)的高级功能,包括Lua脚本自动化和D3D Hook技术,帮助用户从基础内存扫描升级到开发具有专业图形界面的游戏辅助工具。通过实战示例和优化策略,展示了如何创建高效、稳定的游戏辅助系统,并打包为独立训练器。

weixin_28700411的博客 314

用Lua编写iOS程序

原文:http://luanova.org/ioswithlua/  本文讨论用Lua创建iOS应用的3种方法。包括用Lua创建完整的应用(Corona)一直到用Lua作为app中的脚本元素(通过Wax或diy)。在此之前,我们需要问自己两个问题:1、为什么要使用Lua?2、苹果允许使用Lua吗?这两个问题是紧密相关的。如果你在此之前对Lua一无所知,我会简单介绍一下Lua。如果你熟悉Lua,则可

kmyhy的专栏 4万+

从理论到实践:使用Sigrity SystemSI完成DDR4信号完整性仿真全流程解析

本文详细解析了使用Sigrity SystemSI完成DDR4信号完整性仿真的全流程,从核心挑战到实战操作。文章深入探讨了DDR4信号完整性问题,介绍了SystemSI工具链的演进与分工,并提供了从前期准备到高级技巧的详细指南,帮助工程师有效解决DDR4设计中的信号完整性问题。

weixin_30505225的博客 508

labview设置工业摄像头外部触发

使用labview对海康MV-CA013-GM相机设置外部触发。 一、硬件部分 1、硬件引脚定义 2、触发模式设置 相机的触发模式分为两种,一种是内触发模式、另外一种是外触发模式。 3、接线图 信号线的地要跟给信号的设备共地。信号线给高电平时触发拍照。 二、软件部分 1、创建vision acquisition 2、选择使用的摄像头。 3、选择模式。 4、在Acquisition Control中设置这些选项。 5、设置保存图片路径 设置保存路径和保存图片的格式。点击完成即可 参考:https:/

qq_43493715的博客 5665

Lua基础(七)表

一 表的特点 table是Lua'最复杂最强大'的数据结构,Lua本身并'不是面向对象'语言,面向对象中毒比较深的程序员'可以借助'table"完美地模拟"面向对象编程 +++++++++++++++'分割线'+++++++++++++++ 1)表'table'是Lua语言中'最主要'-->'唯一'的强大'数据结构' 2)Lua语言以一种'简单、统一、高效'的方式表示'数组、集合、记录'和其它数据结构 3)Lua语言中'表本质'是一种'辅助数组',类似awk中的"关联数组",数组的索引可.

wzj_110的博客 2937

交换机初始化配置详解

MGMT或称MGT(Management Port,管理端口)是一个可以连接计算机的三层主机端口,如下图所示。只需使用一条双绞线跳线,就可以将计算机的以太网端口与交换机的MGMT端口连接在一起,实现对交换机的配置与管理。也就是说,可以使用MGMT端口代替Console端口实现对交换机或交换机堆叠的网络管理。MGMT端口既可用于交换机的初始化,也可以在交换机初始化完成后,以Telnet、Web浏览器或Cisco CNA方式进行管理。当将计算机连接到独立的交换机时,连接方式如下图所示。

悦分享 1992

Lua5.2源代码解析

源代码版本:lua-5.2.0  一、概览  1、lua脚本中暴露的库相关  lbaselib.c - 基础函数库(方便使用lua内部的功能)  lbitlib.c - 位运算库  lcorolib.c - 协程库  lstrlib.c - 字符串库,提供通用字符串处理功能    lstring.c - 字符串表(保存所有由Lua操作的字符串集合)  lmathlib.c - 数学

intheworld 1152

2026最新YOLO26改进:卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总

针对YOLO26模型改进痛点,本专栏整理200+实战验证方法,覆盖卷积层、注意力机制等核心模块。 每种方法含原理、性能分析、改进路径及实操流程,代码可直接运行,快速提升模型效果,性价比超高。

魔改工程师的博客 1万+

人工智能智能体研究综述:从理论架构到前沿应用

AI Agent,即人工智能智能体,是指能够在特定环境中自主感知、推理、决策并执行行动以实现特定目标的智能系统[1]。自主性反应性主动性(Pro-activeness)和社会性fill:#333;important;important;fill:none;color:#333;color:#333;important;fill:none;fill:#333;height:1em;AI Agent核心特征自主性 Autonomy反应性 Reactivity主动性 Pro-activeness。

nmdbbzcl的博客 902

Lua调用C#相关

使用unity中的成员方法,一点要用:(静态方法依然用.)。xLua中不支持无参泛型函数,所以要用typeof。

qq_45825388的博客 2119

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

冰豹lua驱动设置_通过编写“猜数字”游戏学习 Lua | Linux 中国

通过编写一个简单的游戏来认识 Lua,它是一种动态类型的、轻量级的、高效的、可嵌入的脚本语言。• 来源:linux.cn • 作者:Seth Kenlon • 译者:geekpi •(本文字数:2777,阅读时长大约:3 分钟)如果你是 Bash、Python 或 Ruby 等脚本语言的爱好者,你可能会发现 Lua 很有趣。Lua 是一种动态类型的、轻量级的、高效的、可嵌入的脚本语言,它有与 C ...

weixin_42366533的博客 179

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

【Lua学习】Lua最最基础的

lua最最基础的

weixin_42206314的博客 2070

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Unity3DTraining 之 Xls2Lua:Excel 批量转 Lua 配置表的转表工具实战指南

本文围绕 [XlsxTools/Xls2Lua/README.md](https://link.gitcode.com/i/f2fde449f6c6d16339792104646979a2) 所描述的 Xls2Lua 转表工具展开,讲解如何将 `.xls` 格式的 Excel 配置表批量转换为 Lua 数据文件,并配套一个简易的 ConfigMgr 读取类完成运行期加载。读完本文,你将掌握:转表工

gitblog_00858的博客 219
上一篇: 编写高效Lua代码的方法 - 1 - 基本知识
下一篇: 编写高效Lua代码的方法 - 3 - 字符串
wihing
博客等级 码龄19年 55粉丝 36原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值