Lua性能优化之table_lua table宽容 2幂-程序员宅基地

技术标签: Lua性能优化  Lua  

通常情况下,我们不需要知道Lua的table是如何实现的,但是为了对lua性能进行优化,去了解Lua table的实现细节是非常关键的。

01

table是如何实现的?

为了了解table的实现,我们可以查看Lua的C源码,如下:

 

图1-1 lua表的构成

Lua中的table是由两部分组成,数组部分和哈希表部分。数组部分储存着索引为整型的数据,哈希表存储着以其它类型为索引的键值对。哈希表使用一个哈希算法来计算键值对的key值,采用开链法来处理哈希冲突。当我们声明一个表t = { },此时t的数组部分和哈希表部分的大小都是0,当不断向数组插入键值对的时候 如下:

  • a[1] = 1 ,大小不够,需要扩容,扩容后数组部分的大小为1

  • a[2] = 2 ,大小不够,需要扩容,扩容后数组部分的大小为2

  • a[3] = 3 ,大小不够,需要扩容,扩容后数组大小为4.

执行扩容的过程叫做rehash,每次rehash时,会遍历整个table的数组部分和哈希表部分,统计其中有效的键值对,大小不够,则会扩容,扩容后的大小为2的整数幂次方,且保证rehash操作后整个数组部分的使用率大于50%。每次rehash都很耗时,使用table,我们应该尽量减少rehash。

  

02

如何减少Rehash?

    1.不要使用多个size较小的table,如果可以使用大的table来代替。

    由第一部分可以看到,当table的size从0扩展到4的时候需要3次rehash。因此当table尺寸较小时,向table中插入元素,很容易触发rehash,因此不要过多的使用小table,使用一个大的table来整合小的table。

     2.初始化table的写法。

    对于第一部分的t={},我们可以声明t的时候就对t进行初始化 即:

            t={1,2,3},

    这样会直接产生一个size=3 的表t,也就没有了3次rehash。需要注意的是:

            t ={[1]=1,[2]=2,[3]=3},

    这种写法t的数组部分的大小也为4,会执行三次rehash。

       3.将table置空的注意点

table size大小的变化只会在触发rehash的时候进行,因此当我们将table中的某个键值对的值设置为nil的时候,Lua并不会执行减小size的操作。当执行rehash的时候,Lua才会查找所有为nil的元素,并且决定是否reduce size。例如

        local t = {} 

        for i =1,100000 do

    t[i] = i

end

print(collectgarbage("count"))

--置为nil

for i =1,100000 do 

    t[i]=nil

end

print(collectgarbage("count"))

上面两次结果相同,但是当我们

for i= 100001,200000 do

    t[i] = nil

end

print(collectgarbage("count"))

此时结果会变小,因为当遍历到20000时,发现数组大小不够,触发rehash,rehash会保证数组部分的使用率大于50%,因此会减小数组部分的大小。为nil的也会被删除。

又比如当我们直接声明一个local t ={}  t[100] =1,此时为了保证数组的使用效率大于50%,会直接将键值对{100,1}储存在hash表部分。

 4. 常见的清空table的写法。

    方法一:

             for k in pairs(t) do  t[k] =nil end

    方法二

        while true do

            local k  =next(t,nil)

                if not k then

                    break

                end

             t[k] = nil

        end

第二种写法比第一种写法要耗时。next每次返回当前key的值和下一个不为nil的元素的key。当传入的key为nil的时候,每次返回第一个部位nil的键值对的值。第二种写法每次传入的key都为nil,随着table被不断置为nil,寻找第一个不为nil的键值对,将会越来越耗时。而pair虽然也是用next实现的,但是配合上泛型迭代器for,每个循环都会获得上个循环的状态,因此效率上要快很多。第一种写法等价于:

for k,v in next(t,nil) do,每个循环都将next返回的key传入下一个循环的next。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/kangluo1/article/details/104238041

智能推荐

数据库语法复习

数据库语法通常指的是用于管理和操作数据库的各种命令和语句。这些语法因不同的数据库管理系统(DBMS)而异,但大多数关系型数据库管理系统(RDBMS)都支持SQL(结构化查询语言)作为其核心语言。

OSQP文档学习-程序员宅基地

文章浏览阅读1.3k次,点赞27次,收藏22次。osqp求解器官方文档学习_osqp

开源语音格式speex教程(for iOS)_speex的encode方法-程序员宅基地

文章浏览阅读997次。转自http://www.cocoachina.com/bbs/read.php?tid=114755&keyword=speex最新的编译博客最新的Demo这两天在折腾语音的东西,实现类似微信上对讲机的功能,做了两个Demo,一种使用lib-amr库用amr格式实现的,这个网上有现成的教程,所以还是比较好实现的。另一个是用的speex库,这个提的人很多,但是出教程的不_speex的encode方法

STM32+ESP01S(WIFI)上传温湿度(DHT11)至巴法云+手机app_stm32智能加湿器wifi控制app-程序员宅基地

文章浏览阅读1.5k次,点赞26次,收藏35次。翻东西时发现一个ESP01S模块,想着玩一下本篇学习ESP01S连接巴法云STM32F103C8T6最小系统板ESP01S模块DHT11温湿度传感器本篇为学习总结,只为学习测试基础功能,没有进行太多测试,可能隐藏一些暂未发现的问题,欢迎大佬们指正。_stm32智能加湿器wifi控制app

使用Gabor滤波器进行指纹增强:Matlab源代码详解_指纹gabor增强源码-程序员宅基地

文章浏览阅读228次。接着,我们可以使用wiener2函数进行噪声去除操作,以便更好的进行后续的指纹增强。但是,由于受到外部环境的影响和指纹本身特性的限制,指纹图像往往出现模糊、噪声等问题,使得指纹识别的准确率大大降低。其中,lambda表示滤波器的波长,theta表示滤波器的方向,psi表示滤波器的相位偏移,gamma表示滤波器的宽度,bw表示滤波器的带宽,N表示滤波器的个数。通过以上步骤,我们可以使用Gabor滤波器对指纹图像进行增强,得到更加清晰的指纹图像,提高指纹识别的准确率。_指纹gabor增强源码

(五)Docker 安装 redis镜像+启动redis容器(超详细)-程序员宅基地

文章浏览阅读7.7k次,点赞4次,收藏19次。(五)Docker 安装 redis镜像+启动redis容器(4)、命令参数含义:容器=完整Linuxdocker run:在docker中启动一个容器实例-p 6379:6379:指定宿主机端口与容器端口映射关系,容器与主机映射端口为,主机6379,容器6379,访问Linux端口就能访问到MySQL容器--name redis:容器运行后的名称,创建的容器名称。_redis镜像

随便推点

前端发版缓存问题

前端发版缓存问题

探索潜力:中心化交易所平台币的对比分析

相比之下,市值较低的平台币,如BMX、BGB和MX,具有更大的增长潜力,呈现出更多的增长机会。在过去的一年里,受益于美国股市上比特币 ETF 的上市和比特币供应量的第四次减半,比特币的价格一度飙升至73,000美元以上,达到历史新高。本文旨在为读者提供对这七种选定平台币的全面分析,评估它们的价值和潜力,并研究价格和市值增长指标、回购机制、功能权益以及其发行方的市场表现。随着越来越多的开发者和项目选择在这些区块链上构建应用程序,这些区块链的持续发展有助于提升其原生代币的可用性和需求,从而扩展其使用场景。

C语言:项目实践(贪吃蛇)

相信大家都玩过贪吃蛇这款游戏吧,贪吃蛇是久负盛名的游戏,它也和俄罗斯方块,扫雷等游戏位列经典游戏的行列,那贪吃蛇到底是怎么实现的呢?今天,我就用C语言带着大家一起来实现一下这款游戏,从设计到代码的实现可以帮助我们提升编程能力和逻辑能力

web3以太坊开发,前后端交互中涉及到的合约

在web3以太坊开发中,往往大家交流的时候,会涉及到一些合约相关的词汇,这里重点说两个合约,一个是manager合约,另一个是registry合约。

SpringBoot对接口配置跨域设置

在 Spring Boot 应用中,接口配置跨域(Cross-Origin Resource Sharing,CORS)设置是一个常见的需求,特别是当你的前端应用和后端服务部署在不同的域名下时。

android实现倒计时功能_anroid倒计时播报-程序员宅基地

文章浏览阅读611次。Android中的实现CountDownTimer类专门用来实现时间统计 直接使用这个类,或者自定义一个类 class TimeLooper extends CountDownTimer{ //参数为总时间,时间间隔 public TimeLooper(long millisInFuture, long countDownInterval) {_anroid倒计时播报