Перейти к содержимому
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

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


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

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

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

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

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

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

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

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

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


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