Мне любопытно, существует ли ограничение размера для сериализации в PHP. Можно ли сериализовать массив с 5000 ключами и значениями, чтобы он мог быть сохранен в кеш?
Я надеюсь кэшировать список друзей пользователей на сайте социальной сети, кеш нужно будет обновлять довольно часто, но его нужно будет читать почти на каждой загрузке страницы.
На одной установке сервера я предполагаю, что APC будет лучше, чем memcache для этого.
Как уже многие другие люди ответили уже, просто для удовольствия, вот очень быстрый бенчмарк (смею ли я называть это?) ; рассмотрите следующий код:
$num = 1; $list = array_fill(0, 5000, str_repeat('1234567890', $num)); $before = microtime(true); for ($i=0 ; $i<10000 ; $i++) { $str = serialize($list); } $after = microtime(true); var_dump($after-$before); var_dump(memory_get_peak_usage());
Я запускаю это на PHP 5.2.6 (в комплекте с Ubuntu jaunty).
И, да, есть только ценности; нет ключей; и значения довольно просты: нет объекта, нет подматрицы, нет ничего, кроме строки.
Для $num = 1
вы получаете:
float(11.8147978783) int(1702688)
Для $num = 10
вы получаете:
float(13.1230671406) int(2612104)
И, для $num = 100
, вы получаете:
float(63.2925770283) int(11621760)
Таким образом, кажется, что чем больше каждый элемент массива, тем дольше он (кажется справедливым, на самом деле) . Но, для элементов в 100 раз больше, вы не принимаете 100 раз намного дольше …
Теперь с массивом из 50000 элементов вместо 5000, что означает, что эта часть кода изменяется:
$list = array_fill(0, 50000, str_repeat('1234567890', $num));
При $num = 1
вы получаете:
float(158.236332178) int(15750752)
Учитывая время, которое потребовалось для 1, я не буду запускать это для $ num = 10 или $ num = 100 …
Да, конечно, в реальной ситуации вы не будете делать это 10000 раз; поэтому давайте попробуем всего 10 итераций цикла for.
Для $num = 1
:
float(0.206310987473) int(15750752)
Для $num = 10
:
float(0.272629022598) int(24849832)
И для $num = 100
:
float(0.895547151566) int(114949792)
Да, это почти 1 секунда – и довольно много памяти используется ^^
(Нет, это не производственный сервер: у меня довольно высокий memory_limit на этой машине разработки ^^)
Итак, в конце концов, быть немного короче, чем эти числа – и, да, вы можете иметь числа, которые говорят, что бы вы им ни хотели, – я бы не сказал, что существует «предел», как в «жестком закодированном» в PHP , но вы столкнетесь с одним из следующих:
max_execution_time
(как правило, на веб-сервере не более 30 секунд) memory_limit
(на веб-сервере, как правило, не muco более 32 МБ) Но, если вы действительно сериализуете длинные массивы больших данных , я не уверен, что это будет иметь большое значение …
И вы должны учитывать количество времени / загрузку процессора, используя этот кеш, который может помочь вам получить 😉
Тем не менее, лучший способ узнать – это проверить самостоятельно, с реальными данными 😉
И вы также можете взглянуть на то, что Xdebug может делать, когда дело доходит до профилирования : такая ситуация является одной из тех, для которой она полезна!
Функция serialize () ограничена доступной памятью.
Единственный практический предел – ваша доступная память, поскольку сериализация включает в себя создание строки в памяти.
PHP не ограничен. Сериализация возвращает представление bytestream (string) сериализованной структуры, поэтому вы просто получите большую строку.
Существует никаких ограничений, но помните, что сериализация и неэтериализация имеют стоимость.
Несериализация является исключительно дорогостоящей.
Менее дорогостоящим способом кэширования этих данных будет использование var_export()
как такового (начиная с PHP 5.1.0, он работает с объектами):
$largeArray = array(1,2,3,'hello'=>'world',4); file_put_contents('cache.php', "<?php\nreturn ". var_export($largeArray, true). ';');
Затем вы можете просто получить массив, выполнив следующие действия:
$largeArray = include('cache.php');
Ресурсы обычно не кэшируются.
К сожалению, если у вас есть круглые ссылки в вашем массиве, вам нужно будет использовать serialize()
.
Как было предложено Мыслителем выше:
Вы можете использовать
$string = json_encode($your_array_here);
и декодировать его
$array = json_decode($your_array_here, true);
Это возвращает массив. Он работает хорошо, даже если кодированный массив был многоуровневым.
Ок … еще цифры! (PHP 5.3.0 OSX, отсутствие кэша кода операции)
@ Код Паскаля на моей машине для n = 1 при 10k-итераторах производит:
float(18.884856939316) int(1075900)
Я добавляю unserialize () к указанному выше.
$num = 1; $list = array_fill(0, 5000, str_repeat('1234567890', $num)); $before = microtime(true); for ($i=0 ; $i<10000 ; $i++) { $str = serialize($list); $list = unserialize($str); } $after = microtime(true); var_dump($after-$before); var_dump(memory_get_peak_usage());
производит
float(50.204112052917) int(1606768)
Я предполагаю, что дополнительные 600k или около того являются сериализованной строкой.
Мне было интересно узнать о var_export и его include / eval partner $str = var_export($list, true);
вместо serialize () в оригинале производит
float(57.064643859863) int(1066440)
так что немного меньше памяти (по крайней мере, для этого простого примера), но уже больше времени.
добавление в eval('$list = '.$str.';');
вместо неэтериализации в приведенном выше
float(126.62566018105) int(2944144)
Указывая, что, вероятно, происходит утечка памяти при выполнении eval: – /.
Итак, опять же, это не отличные тесты (я действительно должен изолировать eval / unserialize, помещая строку в локальный var или что-то в этом роде, но я ленив), но они показывают связанные тенденции. var_export кажется медленным.
Нет, нет предела, и это:
set_time_limit(0); ini_set('memory_limit ', -1); unserialize('s:2000000000:"a";');
поэтому вы должны иметь safe.mode = On или расширение, например, Suhosin , иначе он будет потреблять всю память в вашей системе.
Я думаю, что лучше, чем сериализовать, это функция json_encode . Он получил недостаток, что ассоциативные массивы и объекты не различаются, но результат строки меньше и легче читать человеком, поэтому также отлаживать и редактировать.
Если вы хотите кэшировать его (так что я предполагаю, что производительность – это проблема), используйте apc_add вместо этого, чтобы избежать повышения производительности при преобразовании его в кеш-память с добавочной + памятью.
Как указано выше, единственным размером является доступная память.
Несколько других gotchas: serialize'd данные не переносимы между многобайтовыми и однобайтовыми кодировками символов. Классы PHP5 включают в себя байты NUL, которые могут вызвать хаос с кодом, который их не ожидает.
Ваш случай использования звучит так, будто вам лучше использовать базу данных, чтобы сделать это, а не полагаться исключительно на доступные ресурсы PHP. Преимущество использования чего-то типа MySQL заключается в том, что он специально разработан с учетом управления памятью для таких вещей, как хранение и поиск.
Это действительно не забавно постоянно сериализовать и неэтериализовать данные только для обновления или изменения нескольких фрагментов информации.
У меня есть случай, в котором unserialize выдает исключение на большом сериализованном объекте, размер: 65535 (магическое число: 16 бит полный бит = 65536)
Я только что наткнулся на экземпляр, где я думал, что нажимаю верхний предел сериализации.
Я сохраняю сериализованные объекты в базе данных с помощью поля TEXT
mysql.
Предел доступных символов для однобайтовых символов составляет 65 535, поэтому я могу сериализовать гораздо более крупные объекты, чем с PHP. Невозможно их неэтериализовать, поскольку они усекаются пределом поля TEXT
.