serializar una gran matriz en PHP?

Tengo curiosidad, ¿hay un límite de tamaño para serializar en PHP? ¿Sería posible serializar una matriz con 5.000 claves y valores para que pueda almacenarse en una memoria caché?

Espero almacenar en caché la lista de amigos de un usuario en un sitio de red social, la memoria caché deberá actualizarse con bastante frecuencia, pero deberá leerse casi cada página cargada.

En una configuración de servidor único, supongo que APC sería mejor que Memcache para esto.

Como muchas otras personas ya respondieron, solo por diversión, aquí hay un punto de referencia muy rápido (¿me atrevo a llamarlo así?) ; considere el siguiente código:

$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()); 

Estoy ejecutando esto en PHP 5.2.6 (el incluido con Ubuntu jaunty).
Y, sí, solo hay valores; sin llaves; y los valores son bastante simples: ningún objeto, ninguna sub-matriz, nada de cadenas.

Por $num = 1 , obtienes:

 float(11.8147978783) int(1702688) 

Por $num = 10 , obtienes:

 float(13.1230671406) int(2612104) 

Y, por $num = 100 , obtienes:

 float(63.2925770283) int(11621760) 

Por lo tanto, parece que cuanto más grande es cada elemento de la matriz, más tarda (parece justo, en realidad) . Pero, para elementos 100 veces más grandes, no tomas 100 veces más tiempo ...

Ahora, con una matriz de 50000 elementos, en lugar de 5000, lo que significa que esta parte del código ha cambiado:

 $list = array_fill(0, 50000, str_repeat('1234567890', $num)); 

Con $num = 1 , obtienes:

 float(158.236332178) int(15750752) 

Teniendo en cuenta el tiempo que tardó en 1, no ejecutaré esto ni para $ num = 10 ni $ num = 100 ...

Sí, por supuesto, en una situación real, no estarías haciendo esto 10000 veces; intentemos con solo 10 iteraciones del ciclo for.

Por $num = 1 :

 float(0.206310987473) int(15750752) 

Por $num = 10 :

 float(0.272629022598) int(24849832) 

Y por $num = 100 :

 float(0.895547151566) int(114949792) 

Sí, eso es casi 1 segundo, y se usa bastante memoria ^^
(No, este no es un servidor de producción: tengo un memory_limit bastante alto en esta máquina de desarrollo ^^)

Entonces, al final, para ser un poco más corto que esos números , y sí, puede hacer que los números digan lo que quieran , no diría que hay un "límite" como en "codificado" en PHP. , pero terminarás enfrentando a uno de esos:

  • max_execution_time (generalmente, en un servidor web, nunca es más de 30 segundos)
  • memory_limit (en un servidor web, generalmente no es muco más de 32 MB)
  • la carga que tendrá su servidor web: mientras se ejecutaba 1 de esos grandes serialize-loop, tomó 1 de mi CPU; si tienes bastantes usuarios en la misma página al mismo tiempo, te dejo imaginar lo que ofrecerá 😉
  • la paciencia de tu usuario ^^

Pero, excepto si realmente está serializando largas matrices de big data , no estoy seguro de que importe tanto ...
Y debe tener en cuenta la cantidad de tiempo / carga de la CPU que utiliza ese caché podría ayudarlo a ganar 😉

Aún así, la mejor manera de saberlo sería probarlo usted mismo, con datos reales 😉

Y también es posible que desee ver lo que Xdebug puede hacer cuando se trata de perfiles : ¡este tipo de situación es una de las que es útil!

La función serialize () solo está limitada por la memoria disponible.

El único límite práctico es su memoria disponible, ya que la serialización implica la creación de una cadena en la memoria.

No hay límite impuesto por PHP. Serialize devuelve una representación de bitcool (cadena) de la estructura serializada, por lo que solo obtendría una cadena grande.

No hay límite, pero recuerde que la serialización y la deserialización tienen un costo.

La deserialización es extremadamente costosa.

Una forma menos costosa de almacenamiento en caché de esos datos sería a través de var_export() como tal (desde PHP 5.1.0, funciona en objetos):

 $largeArray = array(1,2,3,'hello'=>'world',4); file_put_contents('cache.php', " 

Luego puede simplemente recuperar la matriz haciendo lo siguiente:

 $largeArray = include('cache.php'); 

Los recursos generalmente no son almacenables en caché.

Desafortunadamente, si tiene referencias circulares en su matriz, necesitará usar serialize() .

Como lo sugirió el Pensador anterior:

Podrías usar

 $string = json_encode($your_array_here); 

y decodificarlo

 $array = json_decode($your_array_here, true); 

Esto devuelve una matriz. Funciona bien incluso si la matriz codificada era multinivel.

Ok … ¡más números! (PHP 5.3.0 OSX, sin caché de código de operación)

El código de @ Pascal en mi máquina para n = 1 a 10k iters produce:

 float(18.884856939316) int(1075900) 

Agrego unserialize () a lo anterior como tal.

 $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()); 

produce

 float(50.204112052917) int(1606768) 

Supongo que los 600k adicionales son la cadena serializada.

Tenía curiosidad sobre var_export y su socio include / eval $str = var_export($list, true); en lugar de serialize () en el original produce

 float(57.064643859863) int(1066440) 

tan solo un poco menos de memoria (al menos para este simple ejemplo) pero mucho más tiempo.

añadiendo en eval('$list = '.$str.';'); en lugar de deserializar en lo anterior produce

 float(126.62566018105) int(2944144) 

Indicando que probablemente hay una pérdida de memoria en algún lugar al hacer eval: - /.

Entonces, de nuevo, estos no son grandes puntos de referencia (realmente debería aislar el eval / unserialize poniendo la cadena en una var local o algo así, pero estoy siendo perezoso) pero muestran las tendencias asociadas. var_export parece lento.

No, no hay límite y esto:

 set_time_limit(0); ini_set('memory_limit ', -1); unserialize('s:2000000000:"a";'); 

Es por eso que debe tener safe.mode = On o una extensión como Suhosin instalada , de lo contrario, consumirá toda la memoria de su sistema.

Creo que mejor que serializar es la función json_encode . Obtuvo un inconveniente, que las matrices asociativas y los objetos no se distinguen, pero el resultado de la cadena es más pequeño y más fácil de leer por los humanos, por lo que también se puede depurar y editar.

Si desea almacenarlo en la memoria caché (así que supongo que el rendimiento es el problema), utilice apc_add en su lugar para evitar el impacto en el rendimiento de convertirlo en una cadena + ganar memoria caché.

Como se indicó anteriormente, el único límite de tamaño es la memoria disponible.

Algunos otros errores: los datos serializados no son portátiles entre las codificaciones de caracteres de varios bytes y de un solo byte. Las clases PHP5 incluyen bytes NUL que pueden causar esgulps con código que no los espera.

Su caso de uso parece que es mejor usar una base de datos para hacer eso en lugar de depender únicamente de los recursos disponibles de PHP. Las ventajas de utilizar algo como MySQL en su lugar es que está diseñado específicamente con la gestión de la memoria en mente para cosas como el almacenamiento y la búsqueda.

Realmente no es divertido serializar y deserializar constantemente datos solo para actualizar o cambiar algunas piezas de información.

Tengo un caso en el que “deserializar” arroja una excepción en un gran objeto serializado, tamaño: 65535 (el número mágico: 16 bits completo = 65536)

Acabo de encontrarme con una instancia en la que pensé que estaba llegando a un límite superior de serialización.

Estoy persistiendo en objetos serializados a una base de datos usando un campo de TEXT mysql.

El límite de los caracteres disponibles para los caracteres de un solo byte es 65.535, así que aunque puedo serializar objetos mucho más grandes que eso con PHP, es imposible deserializarlos ya que están truncados por el límite del campo TEXT .