美文网首页
Lua字符串拼接

Lua字符串拼接

作者: 不正经的搬砖工 | 来源:发表于2020-06-29 14:59 被阅读0次

    之前研究lua中字符串拼接,看了一些文章都说 "table.concat" 高于 ".."。最近项目做优化,发现项目中使用table.concat的效率并不比..高,所以实际测试了一下。


    1、一些文章说的"table.concat" 高于 "..",是在特定环境中才有效的,看一下他们使用的测试用例:


    local str = "a"

    local count = 100000

    local start_time = os.clock()

    local result = ""

    for i=1,count do

        result = result .. str

    end

    print("operatorConcatTime:" .. os.clock() - start_time)

    local tbl = {}

    for i=1,count do

        table.insert( tbl,str)

    end

    table.concat(tbl)

    print("tableConcatTime:" .. os.clock() - start_time)


    运行后测试结果如上图,运行效率明显table.concat远高于..。在上述测试用例中,“..” 每次只拼接一个字符串,一共拼了10000次。“..”每次拼接都会产生一个新的字符串,而在lua中每产生一个新的字符串都需要将该字符串存放在全局状态表(global_State)的strt域中,随着拼接次数增大,就会需要更大的空间存储新的字符串,当达到一定大小时,旧的字符串就需要GC,伴随着不断的开辟新空间和GC,就导致性能降低。 而table.concat 底层拼接字符串的方式也是使用运算符.. ,但是其使用算法减少了使用运算符..的次数,减少了GC,从而提高效率。主要思路:采用二分思想,用栈存储字符串,新入栈的字符串与下方的字符串比较长度,大于则使用运算符..拼接成新字符串,并移除栈顶的字符串,不断向下直至遇到长度更大的字符串或者栈底,这样保持最大的字符串位于栈底,栈呈现金字塔的形状,最终在使用运算符..将栈中的字符串拼接成最终的字符串。引用(Lua大量字符串拼接方式效率对比及原因分析_AaronChan的博客-CSDN博客_lua 字符串拼接)。


    2、而在实际项目中一般都是几个字符串的拼接,拼接频次高,拼接个数少。针对项目中实际情况,写了如下测试用例测试:

    (1)测试用例1:

    functionglobal_SpliceString(...)

        local t = {...}

        return table.concat(t)

    end

    local count = 10000

    local sM1 = 0

    local sM2 = 0

    localstart_time

    collectgarbage("collect")

    sM1 =collectgarbage("count")

    print("sM1:",sM1)

    local result = ""

    start_time = os.clock()

    for i = 1, count do            

        result =global_SpliceString("SELECT * FROM ", "QuestPlot", "WHERE sn='", i, "'")

    end

    print("CostTime:",(os.clock() - start_time))

    sM2 =collectgarbage("count")

    print("sM2:",sM2)

    print("Genery Memory:", (sM2 - sM1))

    (2)测试用例2:

    local count = 10000

    local sM1 = 0

    local sM2 = 0

    localstart_time

    collectgarbage("collect")

    sM1 = collectgarbage("count")

    print("sM1:",sM1)

    local result = ""

    start_time = os.clock()

    for i = 1, count do

        result = "SELECT * FROM" .. "QuestPlot" .. " WHERE sn='" .. i .."'"

    end

    print("CostTime:",(os.clock() - start_time))

    sM2 =collectgarbage("count")

    print("sM2:",sM2)

    print("Genery Memory:",(sM2 - sM1))

    (3)测试用例3:

    local tb = {[1]= "SELECT * FROM ", [2] = "QuestPlot", [3] = " WHEREsn='", [4] = 100101, [5] = "'"}

    collectgarbage("collect")

    sM1 =collectgarbage("count")

    print("sM1:",sM1)

    local result = ""

    start_time = os.clock()

    for i = 1, count do

        tb[4] = i

        result = table.concat( tb )

    end

    print("CostTime:",(os.clock() - start_time))

    sM2 =collectgarbage("count")

    print("sM2:",sM2)

    print("Genery Memory:",(sM2 - sM1))


    测试结果如下所示:

    (1)global_SpliceString:

    (2)..

    (3)table.concat:

    为了模仿更真实的使用环境,以上三个测试用例中要拼接的字符串都有一个动态变化的字符串。通过结果比对,测试用例2和用例3的耗时和内存相差无几,而测试用例1的耗时和内存明显高出很多。通过查看lua源码知道,在一个语句中用“..”连续拼接几个字符串并不会产生中间字符串,而是会把所有需要连接的字符串都收集起来一起连接。所以table.concat和“..”的方式相差无几。再看测试用例1,同样使用table.concat,为什么用例1的耗时和内存明显增多。 是因为在gobal_SpliceString()方法中的local t = {...},每次调用这个方法都需要先构造一个table,然后才能使用table.concat。而table在lua中也属于GC对象,table的创建需要消耗更多时间和内存。同时调用global_SpliceString也会有函数调用消耗,所以用例1的性能消耗是由构造table导致的。

    3、总结:

    通过以上分析,我们不能简单的说table.concat和“..”谁的性能更好,还要根据具体使用场景,具体问题具体分析。一般如果一次拼接大量字符串并且要拼接的字符串基本都是固定的,可以使用table缓存起来,使用table.concat拼接;如果是动态的且比较少的字符串拼接,可以直接在一个语句中使用“..”连续拼接。

    相关文章

      网友评论

          本文标题:Lua字符串拼接

          本文链接:https://www.haomeiwen.com/subject/eunnfktx.html