Сериализовать большой массив в PHP?
Мне любопытно, существует ли ограничение размера для сериализации в PHP. Можно ли сериализовать массив с 5000 ключами и значениями, чтобы он мог быть сохранен в кеш?
Я надеюсь кэшировать список друзей пользователей на сайте социальной сети, кеш нужно будет обновлять довольно часто, но его нужно будет читать почти на каждой странице.
На одной установке сервера я предполагаю, что APC будет лучше, чем memcache для этого.
Ответы
Ответ 1
Как уже многие другие люди ответили уже, просто для удовольствия, здесь очень быстрый бенчмарк (смею ли я называть это?); рассмотрите следующий код:
$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 МБ)
- Загрузка вашего веб-сервера будет: в то время как 1 из этих больших циклов сериализации был запущен, он занял 1 из моего процессора; если у вас одновременно есть пара пользователей на одной странице, я позволяю вам представить, что он даст, -)
- терпение вашего пользователя ^^
Но, если вы действительно сериализуете длинные массивы больших данных, я не уверен, что это будет иметь большое значение...
И вы должны учитывать, что время/загрузка процессора с использованием этого кеша может помочь вам получить; -)
Тем не менее, лучший способ узнать - проверить сами, с реальными данными; -)
И вы также можете взглянуть на то, что Xdebug может делать, когда дело доходит до профилирование: такая ситуация является одной из тех, для которой это полезно!
Ответ 2
Функция serialize() ограничена доступной памятью.
Ответ 3
Нет ограничений, установленных PHP. Serialize возвращает представление bytestream (string) сериализованной структуры, поэтому вы просто получите большую строку.
Ответ 4
Единственным практическим ограничением является ваша доступная память, поскольку сериализация включает в себя создание строки в памяти.
Ответ 5
Нет ограничений, но помните, что сериализация и неэтеризация имеют стоимость.
Несериализация является исключительно дорогостоящей.
Менее дорогостоящий способ кэширования этих данных через 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()
.
Ответ 6
Как было предложено Мыслителем выше:
Вы можете использовать
$string = json_encode($your_array_here);
и декодировать его
$array = json_decode($your_array_here, true);
Возвращает массив. Он работает хорошо, даже если кодированный массив был многоуровневым.
Ответ 7
Хорошо... больше номеров! (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.';');
вместо unserialize в приведенном выше выражении дает
float(126.62566018105)
int(2944144)
Указание на то, что, возможно, происходит утечка памяти при выполнении eval: -/.
Так что опять же, это не отличные тесты (я действительно должен изолировать eval/unserialize, помещая строку в локальный var или что-то в этом роде, но я ленив), но они показывают связанные тенденции. var_export кажется медленным.
Ответ 8
Нет, нет предела, и это:
set_time_limit(0);
ini_set('memory_limit ', -1);
unserialize('s:2000000000:"a";');
почему вам следует иметь safe.mode = On или расширение, например, Suhosin, установленное, в противном случае оно будет потреблять всю память в вашей системе.
Ответ 9
Я думаю, что лучше, чем сериализация json_encode. У него есть недостаток, что ассоциативные массивы и объекты не различаются, но результат строки меньше и легче читается человеком, поэтому также можно отлаживать и редактировать.
Ответ 10
Если вы хотите кэшировать его (поэтому я предполагаю, что производительность является проблемой), используйте apc_add вместо этого, чтобы избежать повышения производительности при преобразовании его в кеш-память с строкой + усиление в памяти.
Как указано выше, единственным размером является доступная память.
Несколько других ошибок:
Данные serialize'd не переносимы между многобайтовыми и однобайтовыми кодировками.
Классы PHP5 включают в себя байты NUL, которые могут вызвать хаос с кодом, который их не ожидает.
Ответ 11
Ваш случай использования звучит так, будто вам лучше использовать базу данных, чтобы делать это, а не полагаться исключительно на доступные ресурсы PHP. Преимущество использования чего-то типа MySQL заключается в том, что он специально спроектирован с учетом управления памятью для таких вещей, как хранение и поиск.
На самом деле не повеселиться, постоянно сериализуя и несериализируя данные только для обновления или изменения нескольких фрагментов информации.
Ответ 12
Я только что натолкнулся на случай, когда мне показалось, что я достиг верхнего предела сериализации.
Я сохраняющийся сериализованные объекты в базу данных, используя MySQL TEXT
поля.
Предел доступных символов для однобайтовых символов составляет 65 535, поэтому я могу сериализовать объекты гораздо большего размера, чем в PHP. Невозможно десериализовать их, поскольку они усекаются по пределу поля TEXT
.
Ответ 13
У меня есть случай, в котором unserialize генерирует исключение на большом сериализованном объекте, размер: 65535 (магическое число: 16 бит полный бит = 65536)