Krutoy 1 169 Опубликовано: 16 апреля, 2015 (изменено) Для работы крутой черепашки мне потребовалось быстро сериализировать и передавать по сети большие объемы информации. 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 Изменено 16 апреля, 2015 пользователем Krutoy 4 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Totoro 3 562 Опубликовано: 16 апреля, 2015 (изменено) Полезно. Но ты сравнивал по производительности с библиотекой 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) Изменено 16 апреля, 2015 пользователем Totoro Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Zer0Galaxy 2 187 Опубликовано: 16 апреля, 2015 (изменено) Внутренние методы СС Textutils.serialize не подходили, из за медленного оператора ".." , который добавлял в итоговую строку символы. Поискав готовые решения на сайте lua-users, я нашел подходящий код для сохранения таблиц в файл, и переписал его под работу со строкой. Но ведь там же сплошь и рядом конкатенация. Ты сравнивал по производительности с serialize? Изменено 16 апреля, 2015 пользователем Zer0Galaxy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Krutoy Автор темы 1 169 Опубликовано: 16 апреля, 2015 Полезно. Но ты сравнивал по производительности с библиотекой OC Serialization API? (https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/resources/assets/opencomputers/loot/OpenOS/lib/serialization.lua) Нет, не сравнивал, но попробую сравнить позже. Быстрым просмотром кода я обнаружил что в ОС тоже используется оператор ".." к общей строке Но ведь там же сплошь и рядом конкатенация. Ты сравнивал по производительности с serialize? Производительность не сравнивал, доверился расчетам. Но могу и провести. Суть в том, что в моем коде осуществляется конкатенация коротких подстрок. В стандартных же либах СС и ОС производится добавление символов в общую строку, что намного медленнее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Krutoy Автор темы 1 169 Опубликовано: 16 апреля, 2015 (изменено) Итак, я провел тесты. Результаты потрясающие - почти мой код сериализует в десятки раз быстрее. Для двухмерного массива с 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 Изменено 16 апреля, 2015 пользователем Krutoy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
1Ridav 1 049 Опубликовано: 16 апреля, 2015 Итак, я провел тесты. Результаты потрясающие - почти мой код сериализует в десятки раз быстрее. Для двухмерного массива с 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 169 Опубликовано: 16 апреля, 2015 Не забываем про КЭШ, он сильно искажает показатели тестов, поэтому его надо очищат Нет Рид, не в этом случае. Если запускать отдельно каждую функцию результат идентичный. Пруф для 100 000: http://ideone.com/JZODo2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
1Ridav 1 049 Опубликовано: 16 апреля, 2015 Нет Рид, не в этом случае. Если запускать отдельно каждую функцию результат идентичный. Пруф для 100 000: http://ideone.com/JZODo2 После создания таблицы и её обработки - она попадает в кэш. Она может быть там часами, если её не заменит что либо другое. Так что единственный способ исключить это влияние - заполнять таблицу другими данными перед каждым тестом. Заполнил Сериализовал Заполнил Разсериализовал Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Krutoy Автор темы 1 169 Опубликовано: 16 апреля, 2015 (изменено) После создания таблицы и её обработки - она попадает в кэш. Она может быть там часами, если её не заменит что либо другое. Так что единственный способ исключить это влияние - заполнять таблицу другими данными перед каждым тестом. Заполнил Сериализовал Заполнил Разсериализовал Посмотри первые 30 строк пруфа где я собственно создаю и сериализую таблицу. Я оставил только 1 сериализацию и замер выдает идентичные результаты, даже при отдельном запуске каждого типа сериализации. Изменено 16 апреля, 2015 пользователем Krutoy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах