💢歡迎來到張胤塵的技術站
💥技術如江河,匯聚眾志成。代碼似星辰,照亮行征程。開源精神長,傳承永不忘。攜手共前行,未來更輝煌💥
文章目錄
- Lua | 每日一練 (3)
- 題目
- 參考答案
- 減少查找次數
- 預分配表空間
- 數組部分(連續整數索引)
- 哈希部分(非整數索引)
- 減少嵌套深度
- 避免表中存在非連續索引
- 使用獨立的表
- 避免稀疏數組
- 清理表中的空隙,優化表的結構
- 常使用元表和元方法優化
- 減少垃圾回收的開銷
- 減少全局變量的使用
Lua | 每日一練 (3)
題目
lua
中的 table
性能優化有哪些技巧?
參考答案
table
是 lua
的一種數據結構用來創建不同的數據類型,例如:數組、字典。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
本文中總結的優化點可能不全面,如果大家有更好的優化點,也可以同樣可以在評論區中分享出來~~ 期待😀
🌺🌺🌺撒花!
如果本文對你有幫助,就點關注或者留個👍
如果您有任何技術問題或者需要更多其他的內容,請隨時向我提問。