通常情况下,我们不需要知道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。
数据库语法通常指的是用于管理和操作数据库的各种命令和语句。这些语法因不同的数据库管理系统(DBMS)而异,但大多数关系型数据库管理系统(RDBMS)都支持SQL(结构化查询语言)作为其核心语言。
文章浏览阅读1.3k次,点赞27次,收藏22次。osqp求解器官方文档学习_osqp
文章浏览阅读997次。转自http://www.cocoachina.com/bbs/read.php?tid=114755&keyword=speex最新的编译博客最新的Demo这两天在折腾语音的东西,实现类似微信上对讲机的功能,做了两个Demo,一种使用lib-amr库用amr格式实现的,这个网上有现成的教程,所以还是比较好实现的。另一个是用的speex库,这个提的人很多,但是出教程的不_speex的encode方法
文章浏览阅读1.5k次,点赞26次,收藏35次。翻东西时发现一个ESP01S模块,想着玩一下本篇学习ESP01S连接巴法云STM32F103C8T6最小系统板ESP01S模块DHT11温湿度传感器本篇为学习总结,只为学习测试基础功能,没有进行太多测试,可能隐藏一些暂未发现的问题,欢迎大佬们指正。_stm32智能加湿器wifi控制app
文章浏览阅读228次。接着,我们可以使用wiener2函数进行噪声去除操作,以便更好的进行后续的指纹增强。但是,由于受到外部环境的影响和指纹本身特性的限制,指纹图像往往出现模糊、噪声等问题,使得指纹识别的准确率大大降低。其中,lambda表示滤波器的波长,theta表示滤波器的方向,psi表示滤波器的相位偏移,gamma表示滤波器的宽度,bw表示滤波器的带宽,N表示滤波器的个数。通过以上步骤,我们可以使用Gabor滤波器对指纹图像进行增强,得到更加清晰的指纹图像,提高指纹识别的准确率。_指纹gabor增强源码
文章浏览阅读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语言带着大家一起来实现一下这款游戏,从设计到代码的实现可以帮助我们提升编程能力和逻辑能力
在web3以太坊开发中,往往大家交流的时候,会涉及到一些合约相关的词汇,这里重点说两个合约,一个是manager合约,另一个是registry合约。
在 Spring Boot 应用中,接口配置跨域(Cross-Origin Resource Sharing,CORS)设置是一个常见的需求,特别是当你的前端应用和后端服务部署在不同的域名下时。
文章浏览阅读611次。Android中的实现CountDownTimer类专门用来实现时间统计 直接使用这个类,或者自定义一个类 class TimeLooper extends CountDownTimer{ //参数为总时间,时间间隔 public TimeLooper(long millisInFuture, long countDownInterval) {_anroid倒计时播报