У наданих відповідях вже є багато хороших підходів ( тут , тут і тут ). Якщо швидкість - це те, що ви в першу чергу шукаєте, вам, безумовно, слід подумати про те, щоб виконати роботу за допомогою API Lua C, що в рази швидше, ніж вихідний код Lua. При роботі з попередньо завантаженими шматками (наприклад, функцією завантаження ) різниця не така велика, але все ж значна.
Що стосується чистих рішень Lua, дозвольте мені поділитися цим невеликим еталоном, який я вже зробив. Він охоплює кожну надану відповідь на цю дату та додає кілька оптимізацій. І все-таки основне, що слід врахувати:
Скільки разів вам доведеться перебирати символи в рядку?
- Якщо відповідь "один раз", то вам слід шукати першу частину контрольної позначки ("швидкість сировини").
- В іншому випадку друга частина забезпечить більш точну оцінку, оскільки вона аналізує рядок у таблиці, що набагато швидше перебирається. Ви також повинні розглянути можливість написання простої функції для цього, як запропонував @Jarriz.
Ось повний код:
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))
Приклад виводу (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
Результат:
У моєму випадку string.byte
і string.sub
були найшвидшими з точки зору швидкості сировини. При використанні кеш-таблиці та її повторному використанні 10 разів на цикл string.byte
версія була найшвидшою навіть при перетворенні символів назад у символи (що не завжди потрібно і залежить від використання).
Як ви, напевно, помітили, я зробив деякі припущення на основі своїх попередніх тестів і застосував їх до коду:
- Функції бібліотеки завжди повинні бути локалізовані, якщо вони використовуються всередині циклів, оскільки це набагато швидше.
- Вставка нового елемента в таблицю lua набагато швидша,
tbl[idx] = value
ніж table.insert(tbl, value)
.
- Перегляд таблиці з використанням
for i = 1, #tbl
відбувається трохи швидше, ніж for k, v in pairs(tbl)
.
- Завжди віддайте перевагу версії з меншою кількістю викликів функцій, оскільки сам виклик трохи додає часу виконання.
Сподіваюся, це допоможе.