Ci sono già molti buoni approcci nelle risposte fornite ( qui , qui e qui ). Se la velocità è ciò che stai cercando principalmente , dovresti assolutamente considerare di eseguire il lavoro tramite l'API C di Lua, che è molte volte più veloce del codice Lua grezzo. Quando si lavora con blocchi precaricati (es. Funzione di caricamento ), la differenza non è così grande, ma comunque considerevole.
Per quanto riguarda le soluzioni Lua pure , lasciatemi condividere questo piccolo benchmark che ho realizzato. Copre ogni risposta fornita a questa data e aggiunge alcune ottimizzazioni. Tuttavia, la cosa fondamentale da considerare è:
Quante volte dovrai ripetere i caratteri nella stringa?
- Se la risposta è "una volta", dovresti cercare la prima parte del contrassegno ("velocità grezza").
- Altrimenti, la seconda parte fornirà una stima più precisa, perché analizza la stringa nella tabella, che è molto più veloce da iterare. Dovresti anche considerare di scrivere una semplice funzione per questo, come suggerito da @Jarriz.
Ecco il codice completo:
local str = "Hello World!"
local attempts = 5000000
local reuses = 10
local x, c, elapsed, tbl
local stringbyte, stringchar, stringsub, stringgsub, stringgmatch = string.byte, string.char, string.sub, string.gsub, string.gmatch
print("-----------------------")
print("Raw speed:")
print("-----------------------")
x = os.clock()
for j = 1, attempts do
for i = 1, #str do
c = stringsub(str, i)
end
end
elapsed = os.clock() - x
print(string.format("V1: elapsed time: %.3f", elapsed))
x = os.clock()
for j = 1, attempts do
for c in stringgmatch(str, ".") do end
end
elapsed = os.clock() - x
print(string.format("V2: elapsed time: %.3f", elapsed))
x = os.clock()
for j = 1, attempts do
stringgsub(str, ".", function(c) end)
end
elapsed = os.clock() - x
print(string.format("V3: elapsed time: %.3f", elapsed))
local str2table = function(str)
local ret = {}
for i = 1, #str do
ret[i] = stringsub(str, i)
end
return ret
end
x = os.clock()
for j = 1, attempts do
tbl = str2table(str)
for i = 1, #tbl do
c = tbl[i]
end
end
elapsed = os.clock() - x
print(string.format("V4: elapsed time: %.3f", elapsed))
x = os.clock()
for j = 1, attempts do
tbl = {stringbyte(str, 1, #str)}
for i = 1, #tbl do
c = tbl[i]
end
end
elapsed = os.clock() - x
print(string.format("V5: elapsed time: %.3f", elapsed))
x = os.clock()
for j = 1, attempts do
tbl = {stringbyte(str, 1, #str)}
for i = 1, #tbl do
c = stringchar(tbl[i])
end
end
elapsed = os.clock() - x
print(string.format("V5b: elapsed time: %.3f", elapsed))
print("-----------------------")
print("Creating cache table ("..reuses.." reuses):")
print("-----------------------")
x = os.clock()
for k = 1, attempts do
tbl = {}
for i = 1, #str do
tbl[i] = stringsub(str, i)
end
for j = 1, reuses do
for i = 1, #tbl do
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V1: elapsed time: %.3f", elapsed))
x = os.clock()
for k = 1, attempts do
tbl = {}
local tblc = 1
for c in stringgmatch(str, ".") do
tbl[tblc] = c
tblc = tblc + 1
end
for j = 1, reuses do
for i = 1, #tbl do
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V2: elapsed time: %.3f", elapsed))
x = os.clock()
for k = 1, attempts do
tbl = {}
local tblc = 1
stringgsub(str, ".", function(c)
tbl[tblc] = c
tblc = tblc + 1
end)
for j = 1, reuses do
for i = 1, #tbl do
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V3: elapsed time: %.3f", elapsed))
x = os.clock()
for k = 1, attempts do
tbl = str2table(str)
for j = 1, reuses do
for i = 1, #tbl do
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V4: elapsed time: %.3f", elapsed))
x = os.clock()
for k = 1, attempts do
tbl = {stringbyte(str,1,#str)}
for j = 1, reuses do
for i = 1, #tbl do
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V5: elapsed time: %.3f", elapsed))
x = os.clock()
for k = 1, attempts do
tbl = {stringbyte(str, 1, #str)}
for i = 1, #tbl do
tbl[i] = stringchar(tbl[i])
end
for j = 1, reuses do
for i = 1, #tbl do
c = tbl[i]
end
end
end
elapsed = os.clock() - x
print(string.format("V5b: elapsed time: %.3f", elapsed))
Output di esempio (Lua 5.3.4, Windows) :
Raw speed:
V1: elapsed time: 3.713
V2: elapsed time: 5.089
V3: elapsed time: 5.222
V4: elapsed time: 4.066
V5: elapsed time: 2.627
V5b: elapsed time: 3.627
Creating cache table (10 reuses):
V1: elapsed time: 20.381
V2: elapsed time: 23.913
V3: elapsed time: 25.221
V4: elapsed time: 20.551
V5: elapsed time: 13.473
V5b: elapsed time: 18.046
Risultato:
Nel mio caso, string.byte
e string.sub
sono stati i più veloci in termini di velocità grezza. Quando si utilizza la tabella della cache e la si riutilizza 10 volte per ciclo, la string.byte
versione è risultata più veloce anche durante la riconversione dei charcodes in char (il che non è sempre necessario e dipende dall'utilizzo).
Come probabilmente avrai notato, ho fatto alcune ipotesi basate sui miei precedenti benchmark e le ho applicate al codice:
- Le funzioni di libreria dovrebbero essere sempre localizzate se usate all'interno di loop, perché è molto più veloce.
- Inserimento nuovo elemento nella tabella lua è molto più veloce con
tbl[idx] = value
rispetto table.insert(tbl, value)
.
- Il ciclo attraverso la tabella usando
for i = 1, #tbl
è un po 'più veloce di for k, v in pairs(tbl)
.
- Preferisci sempre la versione con meno chiamate di funzione, perché la chiamata stessa aggiunge un po 'al tempo di esecuzione.
Spero che sia d'aiuto.