LINUX.ORG.RU

lua и боль производительности

 


1

3

@LightDiver, вот пример твоего кейса и наглядный пример, что ты не то оптимизируешь, никаких регэкспов не надо, все проходится прямо. Если у тебя исходные условия - не влезаешь в ограниченную память, то это тоже решабельно.

function mylen(s,n)
    local count
    for i = 1, n do
        count = #s
    end
    return count
end

function u8( s )
    local wstring = {}
    local char = 0
    for i = 1, #s do
        local byte = s:byte(i)
        if byte < 128 then
	       char = char + 1
           wstring[char] = string.char(byte)
        elseif byte >= 194 and byte <= 244 then
            char = char + 1
            if byte <= 223 then
                wstring[char] = string.char(byte)..string.char(s:byte(i+1))
                i = i + 1
            elseif byte <= 239 then
                wstring[char] = string.char(byte)..string.char(s:byte(i+1))..string.char(s:byte(i+2))
                i = i + 2
            else
                wstring[char] = string.char(byte)..string.char(s:byte(i+1))..string.char(s:byte(i+2))..string.char(s:byte(i+3))
                i = i + 3
            end
        end
    end
    return wstring
end

function benchm(s,n)
    local wstring = {}
    for i = 1, n do
        wstring = u8( s )
    end
    return wstring
end

local text = "Привет ♥ мир!"
local wstring = u8(text)

local time = os.clock()
print(mylen(wstring, 100000)) --- <-- TABLE a hundred thousand iterations (omg!)
print("Прошло: " .. os.clock()-time) --- <-- as fast as native #s, since it IS native)

time = os.clock()
benchm(text, 100000) --- <-- Instantination consumes time, but once, need optimization
print("Прошло: " .. os.clock()-time)

print(text)
for i = 2, #wstring do --- <--- wow, ORLY? O_o
    print( wstring[i] ) --- <--- native unicode bychar
end
./test.lua 
13
Прошло: 0.002469
Прошло: 0.41051
Привет ♥ мир!
р
и
в
е
т
 
♥
 
м
и
р
!
★★★★★
Ответ на: комментарий от anonymous

Та не, он просто бомбил, пытаясь достичь невозможного. И тесты настолько резали глаз, что мне стало интересно разобраться. Оказалось, конечно, тесты корявые.

Anoxemian ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Видимо, должно быть

то есть ТС даже не протестировал свой собственный код на функциональность?

function mylen(s,n)
    local count
    for i = 1, n do
        count = #s
    end
    return count
end

@Anoxemian я ни разу в жизни не писал даже хелло ворд на луа, но я уверен, что код выше это бред собачий. Можешь пояснить происходящее?

FishHook
()
Ответ на: комментарий от FishHook

Это то, от чего у него бомбило. Взятие длины однобайтовой строки. Дескать родная функция в 100500 раз быстрее собственной имплементации для мультибайтовой. Оказалось, что это 1. не функция 2. может работать и с многобайтовой)

Anoxemian ★★★★★
() автор топика
Ответ на: комментарий от Anoxemian

Это бенч. 100 000 раз вызывается чтение переменной.

А в чём смысл? Время обращения к диску? К памяти? Так первый раз обратится к диску/памяти, а все остальные 99999 раз будет брать из кэша.

Или ты так тестируешь скорость обращения к кэшу? Из луа?

Chord ★★★★
()

local wstring = u8(text)

Как-то это неправильно, конвертировать строку в таблицу, а потом называть это «native unicode bychar».
В Pluto, да, можно обращаться к элементам строки по индексу, да и то, только для ASCII-строк.

dataman ★★★★★
()
Ответ на: комментарий от Anoxemian

альтернативы? либо массив

Ну, наверное, так будет побыстрее:

local utf8 = require 'utf8'

function str_to_table(s)
    local a = utf8.codes(s, true)
    local chars = {}
    for p, c in utf8.codes(s) do
        table.insert(chars, utf8.char(c))
    end
    return chars
end

local s = "Привет!"

local a = str_to_table(s)

print(#a)

for i = 1, #a do
    print(a[i])
end
dataman ★★★★★
()

Можно вот так, чуть быстрее будет но в luajit будет медленее

local function utf8_to_table_long(str)
    local out = { }
    for i=1,#str do
        local char = str:sub(i,i)
        local byte = char:byte()
        if byte < 128 then -- if ascii
           out[#out+1] = char -- just save
        elseif byte >= 192 then -- any start utf8 bytes more or equal 192
           out[#out+1]= char -- save as new symbol
        elseif byte < 192 then -- any bytes after first utf8 byte less 192
           out[#out] = out[#out]..char -- concat this bytes to utf8 symbol
        else
           error('failed parse utf8 text!')
        end
    end
    return out
end
-------------------------------------------------------------------------------
local function utf8_to_table_short(str)
    local out = { }
    -- unpack string to integers
    local bytes = {str:byte(1,-1)}
    -- prefeth func call
    local chars  = string.char
    for i=1,#str do
        local byte = bytes[i]
        local char = chars(byte)
        if byte < 128 then -- if ascii
           out[#out+1] = char -- just save
        elseif byte >= 192 then -- any start utf8 bytes more or equal 192
           out[#out+1]= char -- save as new symbol
        elseif byte < 192 then -- any bytes after first utf8 byte less 192
           out[#out] = out[#out]..char -- concat this bytes to utf8 symbol
        else
           error('failed parse utf8 text!')
        end
    end
    return out
end
-------------------------------------------------------------------------------
local function utf8_to_table(str)
    -- ~1000000 stack limit
    if #str < 900000 then
      return utf8_to_table_short(str)
    end
    return utf8_to_table_long(str)
end
-------------------------------------------------------------------------------
function bench_b(s,n)
    local wstring = {}
    for i = 1, n do
        wstring = utf8_to_table( s )
    end
    return wstring
end
-------------------------------------------------------------------------------
local text = "Привет ♥ мир!"

collectgarbage('stop')


time = os.clock()
local b = bench_b(text, 100000)
print("Прошло: " .. os.clock()-time)

collectgarbage('restart')


print(table.concat(b,','))
LINUX-ORG-RU ★★★★★
()