從 Lua 5.2 遷移到 5.3

jopen 9年前發布 | 10K 次閱讀 Lua

在 2015 年的新年里, Lua 5.3 發布了 rc3 版

如果回顧 Lua 5.2 的發布歷史,Lua 5.2 的 final 版是在 rc8 之后的 2011 年 12 月 17 日發布的,距離 rc1 的發布日 2011 年 11 月 24 日過去不到 1 個月。我們有理由相信正式版不遠了。( 5.3 的 rc1 是 2014 年 12 月 17 日發布的)

這次升級對 Lua 語言層面的影響非常的小,但新增加的 int64 支持,以及 string pack 、utf8 庫對開發幫助很大。所以我強烈建議正在使用 Lua 5.2 的項目盡快升級到 5.3 。相對而言,當初 5.1 向 5.2 升級的時候就痛苦的多(去掉了 setfenv ,增加了_ENV)。

我計劃在 Lua 5.3 正式發布后,將 skynet 內置的 Lua 版本升級到 5.3 ,然后著手進行 skynet 1.0 的發布工作。

在 skynet 的應用環境下,我還是需要對 lua vm 的實現打一個 patch 讓 不同的 lua vm 間可以共享 Proto 。但這個工作可以先不忙做,等正式發布后再來也可以。

目前可以先逐步升級 skynet 下的 lua 庫。

我已經在 github 項目下創建了一個叫 lua53 的分支,做了一些工作。希望有同學可以幫忙一起 review 這部分代碼。有興趣的同學可以對照 最新的 commits 來檢查這些升級做的變更。

必須做的修改是去掉 unsigned 有關的 api 調用。

lua 5.3 去掉了lua_pushunsignedlua_tounsigned等 api ,現在一律使用lua_pushinteger等。這些 api 默認操作lua_Integer這個數據類型。按文檔的說法,在你的代碼中,應該盡可能的使用lua_Integer。它默認等價于 long long ,至少保證 64 位字長(lua 5.3 可以配置成使用 32bit 整數,但在 skynet 的應用環境不會這么做)。如果需要無符號整數,可以再在 C 代碼中做強制類型轉換。

這部分工作做完后,整個代碼就可以正確編譯了。

但是,和序列化有關的庫還需要為 lua 5.3 優化。因為 lua 5.3 原生支持了整型,不需要全部轉換成 double 類型儲存數字。

之前在做數據序列化工作時(seri 庫 和 bson 庫等),為了區分一個 number 類型到底是浮點數還是整數,我采取的方法是用lua_tonumber和lua_tointeger分別取一次,然后比較兩個數值是否相等。在 lua 5.3 中,直接提供了更高效的lua_isinteger來做判斷。

由于現在直接支持 64bit 整數,就不再需要使用 lightuserdata 來保存長整數了。所以我去掉了int64 庫 。

相應的,相關的庫應該做一些調整。pbc 庫目前沒有打包在 skynet 項目中,但我已經修改完畢,晚一點再放出來。skynet 內自帶的序列化庫,以及 bson ,redis 都需要做一些調整。

btw, 再修改序列化庫時發現一個 bug ,再不支持非對齊地址訪問的架構下會有點問題,這次一并修改了。

lua 5.3 不再提倡使用 bit32 庫,而且這個庫只對 32bit 整數有效,位操作現在提供了原生的操作符支持。(注:xor 是用 ~ 而不是 ^ ,因為 ^ 已經被用于 pow 操作了)我檢索了整個代碼,發現用到 bit32 最多的是那個從 openresty 移植來的 mysql driver 。

但實際上,在 lua 5.3 中不必再使用位操作去解析數據流了。因為有新的 string.pack 這個強大的 api 。比如:

local function _get_byte8(data, i)
  local a, b, c, d, e, f, g, h = strbyte(data, i, i + 7)
  -- XXX workaround for the lack of 64-bit support in bitop:
  local lo = bor(a, lshift(b, 8), lshift(c, 16), lshift(d, 24))
  local hi = bor(e, lshift(f, 8), lshift(g, 16), lshift(h, 24))
  return lo + hi * 4294967296, i + 8
end

這個函數可以被簡化成:

local function _get_byte8(data, i)
    return strunpack("<I8",data,i)
end

在修改過程中,我發現 openresty 里這塊代碼寫的很不 lua ,比如這個 dump 函數,

local function _dump(data)
  local len = #data
  local bytes = new_tab(len, 0)
  for i = 1, len do
    bytes[i] = format("%x", strbyte(data, i))
  end
  return concat(bytes, " ")
end

按 lua 的慣用法應該寫成:

local function _dump(data)
    return string.gsub(data, ".", 
        function(x) return format("%02x ", strbyte(x)) end)
end

這樣既簡潔,性能也好很多。

其實這是個普遍的問題。由于 Lua 天生是門嵌入語言,幾乎所有的 Lua 程序員都用過別的語言。所以許多 Lua 程序員帶著其他語言的經驗來寫。前段時間我就發現過另一個例子。

由于 mysql 這塊改動最多,所以特別需要有人來一起 review 和測試。當然這塊代碼還有很多可以改進的地方,暫時就沒有精力做了。如果有同學有興趣,還可以把那塊尚未完成的編碼設置加進去。

原文  http://blog.codingnow.com/2015/01/lua_52_53.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!