Перейти к содержимому
Krutoy

[OC] [CC] Table to string (сериализация)

Рекомендуемые сообщения

J7TZYgF.png

 

Для работы крутой черепашки мне потребовалось быстро сериализировать и передавать по сети большие объемы информации. 3д массивы, таблицы, и прочее прочее.

Внутренние методы СС Textutils.serialize не подходили, из за медленного оператора ".." , который добавлял в итоговую строку символы.

Поискав готовые решения на сайте lua-users, я нашел подходящий код для сохранения таблиц в файл, и переписал его под работу со строкой.

 

http://pastebin.com/AYB7u25g

 

Код:

 

 

-- ********************************************************************************** --

-- **   Serialize table to string                                                  ** --

-- **                                                                              ** --

-- **   Modified version of http://lua-users.org/wiki/SaveTableToFile              ** --

-- **   By Krutoy242                                                               ** --

-- ********************************************************************************** --

 

-- declare local variables

--// exportstring( string )

--// returns a "Lua" portable version of the string

local function exportstring( s )

  return string.format("%q", s)

end

 

local insert  = table.insert

local tostring= tostring

local ipairs  = ipairs

local pairs   = pairs

local type    = type

 

--// The Save Function

function table.toString(tbl)

  if type(tbl) ~= 'table' then return "" end -- Argument not a table

 

  local charS,charE = "   ","\n"

  local s_tbl = {}

 

  -- initiate variables for save procedure

  local tables,lookup = { tbl },{ [tbl] = 1 }

  insert(s_tbl, "return {"..charE )

 

  for idx,t in ipairs( tables ) do

    insert(s_tbl, "-- Table: {"..idx.."}"..charE )

    insert(s_tbl, "{"..charE )

    local thandled = {}

 

    for i,v in ipairs( t ) do

      thandled = true

      local stype = type( v )

      -- only handle value

      if stype == "table" then

        if not lookup[v] then

          insert( tables, v )

          lookup[v] = #tables

        end

        insert(s_tbl, charS.."{"..lookup[v].."},"..charE )

      elseif stype == "string" then

        insert(s_tbl,  charS..exportstring( v )..","..charE )

      elseif stype == "number" or stype == "boolean" then

        insert(s_tbl,  charS..tostring( v )..","..charE )

      end

    end

 

    for i,v in pairs( t ) do

      -- escape handled values

      if (not thandled) then

 

        local str = ""

        local stype = type( i )

        -- handle index

        if stype == "table" then

          if not lookup then

            insert( tables,i )

            lookup = #tables

          end

          str = charS.."[{"..lookup.."}]="

        elseif stype == "string" then

          str = charS.."["..exportstring( i )..]="

        elseif stype == "number" or stype == "boolean" then

          str = charS.."["..tostring( i )..]="

        end

 

        if str ~= "" then

          stype = type( v )

          -- handle value

          if stype == "table" then

            if not lookup[v] then

              insert( tables,v )

              lookup[v] = #tables

            end

            insert(s_tbl, str.."{"..lookup[v].."},"..charE )

          elseif stype == "string" then

            insert(s_tbl, str..exportstring( v )..","..charE )

          elseif stype == "number" or stype == "boolean" then

            insert(s_tbl, str..tostring( v )..","..charE )

          end

        end

      end

    end

    insert(s_tbl, "},"..charE )

  end

  insert(s_tbl, "}" )

 

  return table.concat(s_tbl)

end

 

--// The Load Function

function table.fromString(s)

  if not s then return end -- Argument not string

  local ftables = loadstring(s)

  if not ftables then return end -- String cant be parsed into function

  local tables = ftables()

  for idx = 1,#tables do

    local tolinki = {}

    for i,v in pairs( tables[idx] ) do

      if type( v ) == "table" then

        tables[idx] = tables[v[1]]

      end

      if type( i ) == "table" and tables[i[1]] then

        insert( tolinki,{ i,tables[i[1]] } )

      end

    end

    -- link indices

    for _,v in ipairs( tolinki ) do

      tables[idx][v[2]],tables[idx][v[1]] =  tables[idx][v[1]],nil

    end

  end

  return tables[1]

end

 

 

  • Userdata, Функции и метотаблицы не сохраняются
  • Сохраняются только простые значения как таблицы, строки, числа а так же true\false

 

Замечу, что в моем коде для сбора строки используется таблица и метод table.concat(), который увеличивает скорость работы в разы.

Код можно использовать как в CС так и в OС. Он добавляет новые методы в глобальную таблицу table и вызывается так:

 

-- Таблица, которую мы превращаем в строку

local obj = {[0]=1, 2, 3, ["fieldName"]=0, {6,7,8}}

-- Сериализация
local s = table.toString(obj)

-- Обратно из строки в таблицу
local _obj = table.fromString(s)

 

 

Результаты для двухмерного массива с 1 000 000 полей и замеры времени выполнения:

//CC textutils
serialize(): 45.94
unserialize(): 1.73

//OC serialization
serialization.serialize(): 40.00
serialization.unserialize(): 0.87

//Krutoy table.tostring:
table.toString(): 1.80
table.fromString(): 1.19 

Пруф для меньшего количества полей:

http://ideone.com/ICpS0L

Изменено пользователем Krutoy

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Полезно. Но ты сравнивал по производительности с библиотекой OC Serialization API?

(https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/resources/assets/opencomputers/loot/OpenOS/lib/serialization.lua)

 

Твой пример под OC:

local serial = require('serialization')

-- Таблица, которую мы превращаем в строку
local obj = {[0]=1, 2, 3, ["fieldName"]=0, {6,7,8}}

-- Сериализация
local s = serial.serialize(obj)

-- Обратно из строки в таблицу
local _obj = serial.unserialize(s)
Изменено пользователем Totoro

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

Внутренние методы СС Textutils.serialize не подходили, из за медленного оператора ".." , который добавлял в итоговую строку символы.

Поискав готовые решения на сайте lua-users, я нашел подходящий код для сохранения таблиц в файл, и переписал его под работу со строкой.

Но ведь там же сплошь и рядом конкатенация. Ты сравнивал по производительности с serialize?

Изменено пользователем Zer0Galaxy

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

Полезно. Но ты сравнивал по производительности с библиотекой OC Serialization API?

(https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/resources/assets/opencomputers/loot/OpenOS/lib/serialization.lua)

Нет, не сравнивал, но попробую сравнить позже.

Быстрым просмотром кода я обнаружил что в ОС тоже используется оператор ".." к общей строке

 

 

Но ведь там же сплошь и рядом конкатенация. Ты сравнивал по производительности с serialize?

Производительность не сравнивал, доверился расчетам. Но могу и провести.

Суть в том, что в моем коде осуществляется конкатенация коротких подстрок. В стандартных же либах СС и ОС производится добавление символов в общую строку, что намного медленнее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Итак, я провел тесты. Результаты потрясающие - почти мой код сериализует в десятки раз быстрее.

 

Для двухмерного массива с 1 000 000 полей замеры времени выполнения:

//CC textutils
serialize(): 45.94
unserialize(): 1.73

//OC serialization
serialization.serialize(): 40.00
serialization.unserialize(): 0.87

//Krutoy table.tostring:
table.toString(): 1.80
table.fromString(): 1.19

Пруф для меньшего количества полей:

http://ideone.com/ICpS0L

Изменено пользователем Krutoy

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Итак, я провел тесты. Результаты потрясающие - почти мой код сериализует в десятки раз быстрее.

 

Для двухмерного массива с 1 000 000 полей замеры времени выполнения:

//CC textutils
serialize(): 45.94
unserialize(): 1.73

//OC serialization
serialization.serialize(): 40.00
serialization.unserialize(): 0.87

//Krutoy table.tostring:
table.toString(): 1.80
table.fromString(): 1.19

Пруф для меньшего количества полей:

http://ideone.com/ICpS0L

Не забываем про КЭШ, он сильно искажает показатели тестов, поэтому его надо очищать

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Не забываем про КЭШ, он сильно искажает показатели тестов, поэтому его надо очищат

Нет Рид, не в этом случае. Если запускать отдельно каждую функцию результат идентичный.

Пруф для 100 000: http://ideone.com/JZODo2

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Нет Рид, не в этом случае. Если запускать отдельно каждую функцию результат идентичный.

Пруф для 100 000: http://ideone.com/JZODo2

После создания таблицы и её обработки - она попадает в кэш. Она может быть там часами, если её не заменит что либо другое. Так что единственный способ исключить это влияние - заполнять таблицу другими данными перед каждым тестом.

Заполнил

Сериализовал

Заполнил

Разсериализовал

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

После создания таблицы и её обработки - она попадает в кэш. Она может быть там часами, если её не заменит что либо другое. Так что единственный способ исключить это влияние - заполнять таблицу другими данными перед каждым тестом.

Заполнил

Сериализовал

Заполнил

Разсериализовал

Посмотри первые 30 строк пруфа где я собственно создаю и сериализую таблицу. Я оставил только 1 сериализацию и замер выдает идентичные результаты, даже при отдельном запуске каждого типа сериализации.

Изменено пользователем Krutoy

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Шалом, я знаю что занимаюсь некропостингом, но всё же надеюсь на помощь. Я профан в lua OC и программировании в целом, я слегка понимаю что тут происходит, но пока только начинаю постигать сие ремесло. Скопировав данный код мне выдало 3 ошибки 

В 16.04.2015 в 12:54, Krutoy сказал:

str = charS.."["..exportstring( i )..]="

        elseif stype == "number" or stype == "boolean" then

          str = charS.."["..tostring( i )..]="

первые 2 были здесь, я вроде справился поставив " перед ]=. 3 же ошибка настигла меня при попытке вызова table.fromString() 

 

В 16.04.2015 в 12:54, Krutoy сказал:

local ftables = loadstring(s)

как я понял функции loadstring() почему то нету. Её надо заменить на какую то другую или подгрузить библиотеку?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
27 минут назад, Artiom сказал:

первые 2 были здесь, я вроде справился поставив " перед ]=. 3 же ошибка настигла меня при попытке вызова table.fromString() 

А что за ошибки были, и что за ошибка сейчас?

 

28 минут назад, Artiom сказал:

str = charS.."["..exportstring( i )..]="

        elseif stype == "number" or stype == "boolean" then

          str = charS.."["..tostring( i )..]="

В глаза бросается отсутствие открывающих кавычек в двух фрагментах кода ]=". Я бы ожидал увидеть "]=".

 

32 минуты назад, Artiom сказал:

как я понял функции loadstring() почему то нету.

В OpenComputers, насколько я помню, нет функции loadstring(), но есть load().

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
46 минут назад, eu_tomat сказал:

Я бы ожидал увидеть "]=".

Ну я собственно это я и сделал, 1 и 2 ошибки были при запуске файла "unexpected symbol near ']' ", 3 уже в интерпретаторе 

lua при обращении к функции table.fromString() примерно:"попытка индексировать переменную со значение nil (глобальная loadstring)"

46 минут назад, eu_tomat сказал:

В OpenComputers, насколько я помню, нет функции loadstring(), но есть load().

я поменял ошибки больше нет, спасибо. Но появилась новая проблема таблицы-массивы (на скрине tb1) обрабатывает нормально, а вот таблицы с ключами (tb) он превращает в пустые таблицы, заменой ipairs на pairs это отчасти решилось. Но эта библиотека разве не должна передавать ключи? У меня она их игнорирует и делает из таблицы с ключами массив(

Снимок экрана 2024-08-08 143157.png

Изменено пользователем Artiom

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
2 часа назад, Artiom сказал:

Но эта библиотека разве не должна передавать ключи?

Кто же её знает, что она должна? Тут надо автора пингануть. Возможно он услышит нас.

@Krutoy Если не трудно, расскажи, как должна твоя библиотека работать с таблицами.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в тему...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...