Мне нужно хранить многомерный ассоциативный массив данных в плоском файле для целей кеширования. Иногда я могу столкнуться с необходимостью преобразовать его в JSON для использования в моем веб-приложении, но в подавляющем большинстве случаев я буду использовать массив непосредственно в PHP.
Было бы более эффективно хранить массив как JSON или как сериализованный массив PHP в этом текстовом файле? Я обнаружил, что в новейших версиях PHP (5.3) json_decode на самом деле быстрее, чем unserialize.
В настоящее время я склоняюсь к хранению массива как JSON, так как мне кажется, что его легче читать человеку. Если это необходимо, его можно использовать как в PHP, так и в JavaScript с очень небольшими усилиями, а из того, что я читал, это, может быть, даже быстрее декодировать (хотя не уверен в кодировке).
Кто-нибудь знает о подводных камнях? У кого-нибудь есть хорошие тесты, чтобы показать преимущества в производительности любого метода?
Ответ 1
Ответ зависит от ваших приоритетов.
Если производительность является вашей абсолютной движущей характеристикой, то, конечно, используйте самый быстрый вариант. Просто убедитесь, что вы полностью понимаете различия, прежде чем сделать выбор.
В отличие от serialize(), вам нужно добавить дополнительный параметр, чтобы сохранить символы UTF-8 нетронутыми: json_encode($array, JSON_UNESCAPED_UNICODE) (иначе он преобразует символы UTF-8 в управляющие последовательности Unicode).
JSON не будет помнить о том, каким был исходный класс объекта (они всегда восстанавливаются как экземпляры stdClass).
Вы не сможете использовать __sleep() и __wakeup() с JSON.
По умолчанию только публичные свойства сериализуются в JSON. (в PHP>=5.4 вы можете реализовать JsonSerializable, чтобы изменить это поведение).
JSON более переносимый
И, вероятно, есть еще несколько различий, о которых я не могу вспомнить в данный момент.
Простой тест на скорость для сравнения:
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
// Создайте большой тестовый массив
// Вам может понадобиться отрегулировать его глубину, чтобы избежать ошибок ограничения памяти
$testArray = fillArray(0, 5);
// Время кодирования json
$start = microtime(true);
json_encode($testArray);
$jsonTime = microtime(true) - $start;
echo "JSON encoded in $jsonTime seconds\n";
// Время сериализации
$start = microtime(true);
serialize($testArray);
$serializeTime = microtime(true) - $start;
echo "PHP serialized in $serializeTime seconds\n";
// Сравнение по времени
if ($jsonTime < $serializeTime) {
printf("json_encode() была примерно на %01.2f%% быстрее, чем serialize()\n", ($serializeTime / $jsonTime - 1) * 100);
}
else if ($serializeTime < $jsonTime ) {
printf("serialize() был примерно на %01.2f%% быстрее, чем json_encode()\n", ($jsonTime
/ $serializeTime - 1) * 100);
} else {
echo "Неопределенно!\n";
}
function fillArray( $depth, $max ) {
static $seed;
if (is_null($seed)) {
$seed = array('a', 2, 'c', 4, 'e', 6, 'g', 8, 'i', 10);
}
if ($depth < $max) {
$node = array();
foreach ($seed as $key) {
$node[$key] = fillArray($depth + 1, $max);
}
return $node;
}
return 'empty';
}
Ответ 2
JSON проще и быстрее, чем формат сериализации PHP, и его следует использовать, если:
Вы храните глубоко вложенные массивы:: json_decode() «Эта функция вернет false, если данные в кодировке JSON глубже 127 элементов».
Вы храните объекты, которые необходимо десериализовать, как правильный класс
Вы взаимодействуете со старыми версиями PHP, которые не поддерживают json_decode
Ответ 3
Вас также может заинтересовать https://github.com/phadej/igbinary, который предоставляет другой «движок» сериализации для PHP. Мои случайные/произвольные цифры «производительности» при использовании PHP 5.3.5 на 64-битной платформе показывают:
JSON:
JSON кодируется за 2.180496931076 секунд
JSON декодируется за 9.8368630409241 секунд
размер сериализованной «строки» : 13993
Родной PHP:
PHP сериализован за 2.9125759601593 секунды
PHP без сериализации за 6.4348418712616 секунд
размер сериализованной «String» : 20769
Бинарный код:
WIN igbinary сериализован за 1.6099879741669 секунд
WIN igbinrary unserialized in 4.7737920284271 seconds
WIN Сериализованная «Строка» Размер : 4467
Таким образом, последний вариант igbinary_serialize() и igbinary_unserialize() быстрее и использует меньше дискового пространства. Я использовал код fillArray(0, 3), как описано выше, но сделал ключи массива более длинными строками. igbinary может хранить те же типы данных, что и родной сериализатор PHP (поэтому нет проблем с объектами и т.д.), и вы можете указать PHP5.3 для использования его для работы с сессиями, если захотите.
Ответ 4
Действительно, это хорошая тема, и после прочтения нескольких ответов я хочу поделиться своими экспериментами по этой теме.
У меня есть пример использования, когда нужно запрашивать какую-то «огромную» таблицу почти каждый раз, когда я обращаюсь к базе данных (не спрашивайте, почему – просто факт). Система кэширования базы данных не подходит, поскольку она не кэширует различные запросы, поэтому я подумал о системах кэширования php.
Я пробовал apcu, но это не соответствовало потребностям, память в этом случае недостаточно надежна. Следующим шагом было кеширование в файл с сериализацией.
В таблице 14355 записей с 18 столбцами, это мои тесты и статистика по чтению сериализованного кеша:
JSON:
Как вы все сказали, главное неудобство с json_encode/json_decode заключается в том, что он все преобразует в экземпляр StdClass (или объект). Если вам нужно его зациклить, вы, вероятно, сделаете преобразование в массив, и да, это увеличит время преобразования:
среднее время: 780,2 мс; использование памяти: 41,5 МБ; размер файла кеша: 3,8 МБ
Msgpack
среднее время: 497 мс; использование памяти: 32 МБ; размер файла кеша: 2,8 МБ
Так лучше, но требуется дополнительное расширение.
IgBinary
Обратите внимание, что я установил, igbinary.compact_strings=Off, потому что меня больше волнует производительность чтения, чем размер файла.
среднее время: 411,4 мс; использование памяти: 36,75 МБ; размер файла кеша: 3,3 МБ
Лучше, чем Msgpack. Тем не менее, этот тоже требует компиляции.
serialize/unserialize
среднее время: 477,2 мс; использование памяти: 36,25 МБ; размер файла кеша: 5,9 МБ
Лучшая производительность, чем у JSON: чем больше массив, тем медленнее json_decode, но вы уже знаете это.
Эти внешние расширения сужают размер файла и отлично выглядят на бумаге. Какой смысл компилировать расширение, если вы получаете почти те же результаты, что и со стандартной функцией PHP?
Мы также можем сделать вывод, что в зависимости от ваших потребностей вы выберете что-то другое, что-то типа этого:
IgBinary действительно хорош и работает лучше, чем MsgPack;
Msgpack лучше сжимает ваши данные (обратите внимание, что я не пробовал опцию igbinary compact.string);
Не хотите компилировать? Используйте стандартные способы.
Все было протестировано с помощью PHPUnit 3.7.31, php 5.5.10 - только декодирование со стандартным жестким диском и старым двухъядерным процессором - средние значения по 10 тестам с одним и тем же сценарием использования, ваша статистика может отличаться.
Web