最佳化編碼技巧

lua-users home
wiki

Lua 5.1 注記

--DavidManura

請注意,Roberto Ierusalimschy 的文章《Lua 效能訣竅》取自出色的 [Lua Programming Gems] 書籍,[可線上取得]

Lua 4 注記

以下資訊涉及 Lua 4 的最佳化,保留在此處以供歷史參考。

編碼一般建議

(Joshua Jensen) 以下是我的部分最佳化策略(信手拈來)

此資訊針對 v4.0 之前的 Lua 編寫 -- Nick Trout

宣告

搭配非平凡的訊息表達式,使用標準宣告函式會對指令碼效能產生負面的影響。這是因為,即使在宣告為真時,系統仍然會評估訊息表達式。例如在
assert(x <= x_max, "exceeded maximum ("..x_max..")")
無關乎條件(通常為真)如何,系統都會執行浮點數轉字串轉換以及兩個繼接運算子。下列替代版本會使用 printf 樣式的訊息格式化,並且不會在訊息未被使用時產生訊息
function fast_assert(condition, ...)
    if not condition then
        if getn(arg) > 0 then
            assert(condition, call(format, arg))
        else
            assert(condition)
        end
    end
end
範例現在會變成
fast_assert(x <= x_max, "exceeded maximum (%d)", x_max)

這是產生的 VM 程式碼

assert(x <= x_max, "exceeded maximum ("..x_max..")")
        GETGLOBAL  	0	; assert
        GETGLOBAL  	1	; x
        GETGLOBAL  	2	; x_max
        JMPLE      	1	; to 6
        PUSHNILJMP 	
        PUSHINT    	1
        PUSHSTRING 	3	; "exceeded maximum ("
        GETGLOBAL  	2	; x_max
        PUSHSTRING 	4	; ")"
        CONCAT     	3
        CALL       	0 0
fast_assert(x <= x_max, "exceeded maximum (%d)", x_max)
        GETGLOBAL  	5	; fast_assert
        GETGLOBAL  	1	; x
        GETGLOBAL  	2	; x_max
        JMPLE      	1	; to 17
        PUSHNILJMP 	
        PUSHINT    	1
        PUSHSTRING 	6	; "exceeded maximum (%d)"
        GETGLOBAL  	2	; x_max
        CALL       	0 0

Edit: April 23, 2012 By Sirmabus
The code above will not actually work with 5.1
Also added some enhancements like pointing back to the actual assert line number,
and a fall through in case the assertion msg arguments are wrong (using a "pcall()").

function fast_assert(condition, ...)
   if not condition then
      if next({...}) then
         local s,r = pcall(function (...) return(string.format(...)) end, ...)
         if s then
            error("assertion failed!: " .. r, 2)
         end
      end
      error("assertion failed!", 2)
   end
end

快速非排序清單反覆運算

在 Lua 中,我們常常會建立一個元素表格,例如
table = { "harold", "victoria", "margaret", "guthrie" } 

對這個表格執行反覆運算的「適當」方式如下

for i=1, getn(table) do
    -- do something with table[i]
end

然而,如果我們不關心元素順序,上面的反覆運算會很慢。第一個問題是,它會呼叫 getn(),根據以上假設「n」欄位尚未設定,並且假設其順序為 O(n)。第二個問題是,會執行位元組碼,並執行表格查找以存取每一個元素(也就是「table[i]」)。

一個解決方案是使用表格反覆運算器

for x, element in pairs(table) do
    -- do something with element
end

已經移除 getn() 呼叫和表格查找。這個「x」是一個虛擬變數,因為這個範例中通常不會使用元素索引。

這個解決方案有一個注意事項。如果對表格使用函式庫函式 tinsert() 或 tremove(),它們會設定「n」欄位,該欄位會顯示在我們的反覆運算中。

另一個替代方案是使用 LuaPowerPatches 中列出的清單反覆運算修補程式。

表格存取

問題:我擔心的不是建立表格的效能,而是對於表格內容的所有存取。

(lhf) 表格是 Lua 中的核心資料結構。你不需要擔心表格效能,我們付出了大量的努力以使表格處理飛快。例如,我們有一個特別的指令碼用於 a.x。觀察 a.xa[x] 的不同 ... 但就像你說的,這裡不同之處主要在於額外的 GETGLOBAL

a,c = {},"x"
        CREATETABLE	0
        PUSHSTRING 	2	; "x"
        SETGLOBAL  	1	; c
        SETGLOBAL  	0	; a
b=a.x
        GETGLOBAL  	0	; a
        GETDOTTED  	2	; x
        SETGLOBAL  	3	; b
b=a["x"]
        GETGLOBAL  	0	; a
        GETDOTTED  	2	; x
        SETGLOBAL  	3	; b
b=a[c]
        GETGLOBAL  	0	; a
        GETGLOBAL  	1	; c
        GETTABLE   	
        SETGLOBAL  	3	; b
        END


另請參閱:VmMerge(用於將合併的 Lua 來源和 VM 程式碼格式化)、OptimisationTipsOptimisingUsingLocalVariables


RecentChanges · 偏好設定
編輯 · 歷史記錄
最後編輯時間為 2012 年 4 月 24 日上午 7:42 GMT (diff)