Sudah ada banyak pendekatan yang baik dalam jawaban yang diberikan (di sini , di sini dan di sini ). Jika kecepatan adalah apa yang Anda terutama mencari, Anda pasti harus mempertimbangkan melakukan pekerjaan melalui Lua C API, yang banyak kali lebih cepat daripada kode Lua mentah. Saat bekerja dengan potongan yang dimuat sebelumnya (mis. Fungsi beban ), perbedaannya tidak terlalu besar, tetapi masih cukup besar.
Adapun solusi Lua murni , izinkan saya membagikan patokan kecil ini, yang telah saya buat. Ini mencakup setiap jawaban yang diberikan hingga tanggal ini dan menambahkan beberapa pengoptimalan. Namun, hal dasar yang perlu dipertimbangkan adalah:
Berapa kali Anda perlu mengulang karakter dalam string?
- Jika jawabannya "sekali", maka Anda harus mencari bagian pertama dari banchmark ("kecepatan mentah").
- Jika tidak, bagian kedua akan memberikan estimasi yang lebih tepat, karena mengurai string ke dalam tabel, yang jauh lebih cepat untuk diiterasi. Anda juga harus mempertimbangkan untuk menulis fungsi sederhana untuk ini, seperti saran @Jarriz.
Ini kode lengkapnya:
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))
Contoh keluaran (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
Hasil:
Dalam kasus saya, string.byte
dan string.sub
tercepat dalam hal kecepatan mentah. Saat menggunakan tabel cache dan menggunakannya kembali 10 kali per loop, string.byte
versinya adalah yang tercepat bahkan saat mengonversi kode karakter kembali ke karakter (yang tidak selalu diperlukan dan bergantung pada penggunaan).
Seperti yang mungkin Anda perhatikan, saya telah membuat beberapa asumsi berdasarkan tolok ukur saya sebelumnya dan menerapkannya ke kode:
- Fungsi perpustakaan harus selalu dilokalkan jika digunakan di dalam loop, karena jauh lebih cepat.
- Memasukkan elemen baru ke dalam tabel lua jauh lebih cepat menggunakan
tbl[idx] = value
daripada table.insert(tbl, value)
.
- Perulangan melalui tabel menggunakan
for i = 1, #tbl
sedikit lebih cepat dari for k, v in pairs(tbl)
.
- Selalu lebih suka versi dengan lebih sedikit pemanggilan fungsi, karena pemanggilan itu sendiri menambah sedikit waktu eksekusi.
Semoga membantu.