Lua | 每日一练 (3)

💢欢迎来到张胤尘的技术站
💥技术如江河,汇聚众志成。代码似星辰,照亮行征程。开源精神长,传承永不忘。携手共前行,未来更辉煌💥

文章目录

  • Lua | 每日一练 (3)
    • 题目
    • 参考答案
      • 减少查找次数
      • 预分配表空间
        • 数组部分(连续整数索引)
        • 哈希部分(非整数索引)
      • 减少嵌套深度
      • 避免表中存在非连续索引
        • 使用独立的表
        • 避免稀疏数组
        • 清理表中的空隙,优化表的结构
      • 常使用元表和元方法优化
      • 减少垃圾回收的开销
      • 减少全局变量的使用

Lua | 每日一练 (3)

题目

lua 中的 table 性能优化有哪些技巧?

参考答案

tablelua 的一种数据结构用来创建不同的数据类型,例如:数组、字典。table 的能力是非常强大的,但是如果在使用过程中不注意优化细节,可能会性能产生一定的影响。

下面针对使用 table 过程中的常见优化手段进行总结。

减少查找次数

lua 中,表查找(尤其是多重嵌套表的查找)可能会因为频繁的键访问而变得相对低效。例如:

local myTable = {nested = {value = 10}
}-- 低效:每次循环都进行表查找
for i = 1, 1000000 dolocal v = myTable.nested.value-- 使用 v 做一些操作
end

如果某个表的值在循环或其他频繁执行的代码块中被多次访问,可以将其缓存到局部变量中。这样可以避免每次访问时都进行表查找。

修改后的代码如下所示:

local myTable = {nested = {value = 10}
}-- 高效:将值缓存到局部变量
local cachedValue = myTable.nested.value
for i = 1, 1000000 dolocal v = cachedValue-- 使用 v 做一些操作
end

另外如果需要频繁的访问某个表,可以键表本身缓存到局部变量中,这样可以减少每次访问时的查找路径,例如:

local myTable = {nested = {value = 10}
}-- 低效:每次访问都从根表开始查找
for i = 1, 1000000 dolocal v = myTable.nested.value-- 使用 v 做一些操作
end

修改后的代码如下所示:

local myTable = {nested = {value = 10}
}-- 高效:缓存嵌套表的引用
local nestedTable = myTable.nested
for i = 1, 1000000 dolocal v = nestedTable.value-- 使用 v 做一些操作
end

预分配表空间

经常在循环中进行表分配,频繁的表分配会增加垃圾回收的负担,从而影响性能。

因为 lua 中的表分为数组部分和哈希部分,所以预分配表也分为两部分:预分配数组部分、预分配哈希部分。

数组部分(连续整数索引)

如果表主要用于存储连续的整数索引数据(类似数组),可以通过以下方式预分配空间:

local size = 100000  -- 预分配的大小
local t = {}
t[size] = true  -- 触发预分配

通过将表的最后一个索引位置赋值,lua 会为表的数组部分分配足够的空间,从而避免后续插入元素时的扩容操作。

哈希部分(非整数索引)

如果表主要用于存储非整数索引(如字符串键),可以通过以下方式预分配哈希部分的空间:

local size = 100000  -- 预分配的大小
local t = {}
for i = 1, size dot["key" .. i] = true  -- 触发哈希部分的预分配
end

减少嵌套深度

嵌套表的深度会影响查找效率。如果可能,尽量减少表的嵌套层级,或者将常用的数据提升到更浅的层级。例如:

-- 原始结构
local myTable = {level1 = {level2 = {value = 10}}
}-- 访问优化前的表
local k = myTable.level1.level2.value-- 优化:减少嵌套层级
local myTable = {value = 10,level1 = {-- 其他数据}
}-- 访问优化后的表
local v = myTable.value

避免表中存在非连续索引

由于表可以同时作为数组(连续索引)也可以作为哈希表(非连续索引),那么当表中同时存在连续索引和非连续索引时,可能会导致性能下降和内存浪费。

首先需要搞明白为什么存在非连续会影响性能?

  • 第一,如果表中同时存在连续索引和非连续索引,lua 会同时维护这两部分,导致内存分配和管理变得更加复杂,增加了内存开销。
  • 第二,对于连续索引的数组,lua 可以通过简单的指针偏移快速访问元素;而对于非连续索引,lua 需要进行哈希查找,这会增加访问时间。
  • 第三,非连续索引的表会增加垃圾回收的复杂性,因为 lua 需要同时处理数组部分和哈希部分的内存回收。
使用独立的表

如果需要存储不同类型的数据(数组和哈希表),建议使用两个独立的表,而不是混合在同一个表中。例如:

-- 混合使用
local t = {1, 2, 3}
t["key"] = "value"-- 使用两个独立的表
local array = {1, 2, 3}
local hash = {key = "value"}
避免稀疏数组

稀疏数组(即存在大量空隙的数组)会导致表的内部结构变得复杂。如果需要使用稀疏数组,建议使用哈希表代替。例如:

-- 稀疏数组
local t = {}
t[1] = 1
t[1000000] = 1000000  -- 导致表内部结构复杂化-- 使用紧凑的哈希表结构
local t = {}
t["key1"] = 1
t["key2"] = 1000000
清理表中的空隙,优化表的结构

如果表中存在非连续索引,可以通过重新排序或清理空隙来优化表的结构。例如:

local t = {1, 2, nil, 4, 5}
local new_t = {}
for i, v in ipairs(t) doif v ~= nil thentable.insert(new_t, v)end
end
t = new_t

常使用元表和元方法优化

元表和元方法可以用于优化面向对象的代码,减少函数调用次数,并通过元方法实现高效的常见操作,例如:

local Vector = {}function Vector:new(x, y)local obj = {}setmetatable(obj, self)self.__index = selfself.__add = function(a, b)return Vector:new(a.x + b.x, a.y + b.y)endobj.x = xobj.y = yreturn obj
endlocal v1 = Vector:new(1, 2)
local v2 = Vector:new(3, 4)
local v3 = v1 + v2print(v3.x, v3.y)

减少垃圾回收的开销

垃圾回收的频率会影响性能。通过重用表、避免不必要的分配以及合理调整垃圾回收参数,可以减少垃圾回收的开销。例如:

collectgarbage("setpause", 100)  -- 设置暂停时间
collectgarbage("setstepmul", 200)  -- 设置每次回收的步长

减少全局变量的使用

lua 中,全局变量的访问速度比局部变量慢,因为 lua 需要遍历全局环境来进行查找。局部变量则直接存储在栈上,访问速度更快。另外将表定义为局部变量,可以减少全局环境的污染,提高访问速度。例如:

-- 全局表
myGlobalTable = {value = 10}function globalTableAccess()for i = 1, 1000000 dolocal v = myGlobalTable.valueend
end-- 局部表
local myLocalTable = {value = 10}function localTableAccess()for i = 1, 1000000 dolocal v = myLocalTable.valueend
end

本文中总结的优化点可能不全面,如果大家有更好的优化点,也可以同样可以在评论区中分享出来~~ 期待😀

🌺🌺🌺撒花!

如果本文对你有帮助,就点关注或者留个👍
如果您有任何技术问题或者需要更多其他的内容,请随时向我提问。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/71664.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二叉树(中等题)

1、先序,中序遍历确定二叉树 105 方法一、 前提 ① 必须不能有重复元素② 只有先序+中序和后序+中序才能实现唯一树 思考要点: 不要想着用for循环,递归一定更好解决输入是vector,递归就得考虑传入索…

服务器通过 ollama 运行deepseek r1

1、服务器环境简介 56核 CPU64G 内存无显卡已安装 Ollama 2、下载模型与配置 正常可以通过 ollama pull 或 ollama run 命令直接下载,但通常会遇到连接超时、找不到网址等总理。因此,可以使用国内的模型站进行下载,在这里使用魔塔查找模型…

java项目排查线上问题1111

1.磁盘容量不足: 应用抛出的异常信息:java.io.IOException: 磁盘空间不足 1.1 指令获取磁盘状态:df -h 1.2 获取目录下文件夹大小:du -sh * 1.3 获取目录下文件夹大小:ls -lh 可以找到最大的文件,如日…

js中 ES6 新特性详解

ES6(ECMAScript 2015)是 JavaScript 的一次重大更新,引入了许多新的特性,使 JavaScript 代码更加简洁、可读和高效。以下是 ES6 的主要新特性及其原理 1. let 和 const 关键字 原理解析 1.1 作用域 var 关键字的作用域&#xf…

深入理解设计模式之解释器模式

深入理解设计模式之解释器模式 在软件开发的复杂世界中,我们常常会遇到需要处理特定领域语言的情况。比如在开发一个计算器程序时,需要解析和计算数学表达式;在实现正则表达式功能时,要解析用户输入的正则表达式来匹配文本。这些场景都涉及到对特定语言的解释和执行,而解…

巧妙实现右键菜单功能,提升用户操作体验

在动态交互式图库中,右键菜单是一项能够显著提升用户操作便捷性的功能。它的设计既要响应用户点击位置,又需确保菜单功能与数据操作紧密结合,比如删除图片操作。以下将通过一段实际代码实现,展示从思路到实现的详细过程。 实现右键…

​​​​​​​​​​​​​​如何使用函数指针来调用函数

在C和C编程中,函数指针是一种特殊类型的指针,它指向一个函数而不是一个变量。使用函数指针可以动态地调用不同的函数,这在实现回调函数、事件处理、策略模式等场景中非常有用。 以下是如何定义和使用函数指针来调用函数的步骤: 定…

KEGG条形图绘制

原始数据 setwd("C:\\Users\\HUAWEI\\Desktop\\proteomic_WGCNA\\bacteria\\Eggnog\\KEGGhun") library(ggplot2) library(cols4all) dt <- read.csv("bacteria_KEGG.csv")dt$KEGG_Term <- factor(dt$KEGG_Term, levels rev(dt$KEGG_Term))#基础富集…

My Metronome for Mac v1.4.2 我的节拍器 支持M、Intel芯片

应用介绍 My Metronome 是一款适用于 macOS 的专业节拍器应用程序&#xff0c;旨在帮助音乐家、作曲家、学生和任何需要精确节奏控制的人进行练习。无论是进行乐器练习、音乐创作还是演出排练&#xff0c;My Metronome 都能为用户提供精准的节拍支持和灵活的功能&#xff0c;确…

宇树科技13家核心零部件供应商梳理!

2025年2月6日&#xff0c;摩根士丹利&#xff08;Morgan Stanley&#xff09;发布最新人形机器人研报&#xff1a;Humanoid 100: Mapping the Humanoid Robot Value Chain&#xff08;人形机器人100&#xff1a;全球人形机器人产业链梳理&#xff09;。 Humanoid 100清单清单中…

Part 3 第十二章 单元测试 Unit Testing

概述 第十二章围绕单元测试展开&#xff0c;阐述了单元测试的实践与重要性&#xff0c;通过对比其他测试类型&#xff0c;突出其特点&#xff0c;还介绍了单元测试的最佳实践、避免的反模式以及与测试替身相关的内容&#xff0c;为编写高质量单元测试提供指导。 章节概要 1…

【Vite SVG 图标方案:vite-plugin-svg-icons 指南】

&#x1f31f; Vite SVG 图标方案&#xff1a;vite-plugin-svg-icons 指南 &#x1f4dc; 背景与痛点 &#x1f30d; 前端图标演进史 1.0 &#x1f5bc;️ 图片图标 → 2.0 &#x1f3ad; 字体图标 → 3.0 &#x1f3a8; SVG 图标传统方案存在三大痛点&#xff1a; 字体图标…

go flag参数 类似Java main 的args

两部分内容 go run test1.go aa -name 123 1. 解析&#xff1a;aa -name 123 2. 解析&#xff1a;name 123 代码 package mainimport ("log""os" )func main() {log.Println("main ...")if len(os.Args) > 0 {for index, arg : ra…

酒店旅游API:数据交互的隐形桥梁——以携程API为例

一、API&#xff1a;酒店 和第三方服务无缝连接。 核心价值&#xff1a; 实时数据互通&#xff1a;房态、价格、库存秒级同步。业务流程自动化&#xff1a;预订、支付、确认全程无需人工干预。生态扩展&#xff1a;开发者可基于API构建定制化工具&#xff08;如比价插件、智能…

深入理解 JSP 与 Servlet:原理、交互及实战应用

一、引言 在 Java Web 开发领域,JSP(JavaServer Pages)和 Servlet 是两个至关重要的技术,它们共同构成了动态网页开发的基础。Servlet 作为服务器端的 Java 程序,负责处理客户端请求并生成响应;而 JSP 则是一种简化的 Servlet 开发方式,允许开发者在 HTML 页面中嵌入 J…

【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter20-JavaScript API

二十、JavaScript API JavaScript API 随着 Web 浏览器能力的增加&#xff0c;其复杂性也在迅速增加。从很多方面看&#xff0c;现代 Web 浏览器已经成为构建于诸多规范之上、集不同 API 于一身的“瑞士军刀”。浏览器规范的生态在某种程度上是混乱而无序的。一些规范如 HTML5&…

AI芯片的关键特征

AI芯片是专门为人工智能应用设计的芯片&#xff0c;以下是其应具备的关键特征&#xff1a; 强大的并行计算能力&#xff1a;AI任务如深度学习中的神经网络训练和推理&#xff0c;涉及大量矩阵运算和并行数据处理。AI芯片需有众多计算单元&#xff08;如GPU的大量流处理器、ASIC…

go 模块管理

go version 查看版本 go version go1.21.12 windows/amd64 需要保证:go的版本升级为1.11以上,go mod依赖的最底版本 go env 查看go的环境变量 go env 开启go mod # 标识开启go的模块管理 set GO111MODULE=on GO111MODULE有三个值:off, on和auto(默认值)。 GO111M…

Unity 适用于单机游戏的红点系统(前缀树 | 数据结构 | 设计模式 | 算法 | 含源码)

文章目录 功能包括如何使用 功能包括 红点数据本地持久化 如果子节点有红点&#xff0c;父节点也要显示红点&#xff0c;父节点红点数为子节点红点数的和&#xff1b; 当子节点红点更新时&#xff0c;对应的父节点也要更新&#xff1b; 当所有子节点都没有红点时&#xff0c…

使用API有效率地管理Dynadot域名,为域名部署DNS安全拓展(DNSSEC)

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…