Intereting Posts

сериализовать большой массив в PHP?

Мне любопытно, существует ли ограничение размера для сериализации в 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 МБ)
  • на загрузку вашего веб-сервера будет: в то время как 1 из этих больших циклов сериализации был запущен, он занял 1 из моего процессора; если у вас одновременно есть пара пользователей на одной странице, я могу представить, что это даст 😉
  • терпение вашего пользователя ^^

Но, если вы действительно сериализуете длинные массивы больших данных , я не уверен, что это будет иметь большое значение …
И вы должны учитывать количество времени / загрузку процессора, используя этот кеш, который может помочь вам получить 😉

Тем не менее, лучший способ узнать – это проверить самостоятельно, с реальными данными 😉

И вы также можете взглянуть на то, что 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 .