Pregunta ¿qué es más rápido: in_array o isset? [cerrado]


Esta pregunta es solo para mí, ya que siempre me gusta escribir código optimizado que también se puede ejecutar en servidores lentos baratos (o servidores con MUCHO tráfico)

Miré a mi alrededor y no pude encontrar una respuesta. Me preguntaba qué es más rápido entre esos dos ejemplos teniendo en cuenta que las claves de la matriz en mi caso no son importantes (pseudocódigo, naturalmente):

<?php
$a = array();
while($new_val = 'get over 100k email addresses already lowercased'){
    if(!in_array($new_val, $a){
        $a[] = $new_val;
        //do other stuff
    }
}
?>

<?php
$a = array();
while($new_val = 'get over 100k email addresses already lowercased'){
    if(!isset($a[$new_val]){
        $a[$new_val] = true;
        //do other stuff
    }
}
?>

Como el punto de la pregunta no es la colisión de la matriz, me gustaría añadir que si tiene miedo de colisiones de insertos para $a[$new_value], puedes usar $a[md5($new_value)]. aún puede causar colisiones, pero podría llevar a un posible ataque DoS cuando se lee desde un archivo proporcionado por el usuario (http://nikic.github.com/2011/12/28/Supercolliding-a-PHP-array.html)


73
2017-11-20 22:20


origen


Respuestas:


Las respuestas hasta ahora son acertadas. Utilizando isset en este caso es más rápido porque

  • Utiliza una búsqueda de hash O (1) en la tecla mientras in_array debe verificar cada valor hasta que encuentre una coincidencia.
  • Al ser un código de operación, tiene menos gastos generales que llamar al in_array función incorporada.

Esto se puede demostrar usando una matriz con valores (10,000 en la prueba a continuación), forzando in_array para hacer más búsqueda.

isset:    0.009623
in_array: 1.738441

Esto se basa en el índice de referencia de Jason al completar algunos valores aleatorios y, ocasionalmente, al encontrar un valor que existe en el conjunto. Todo al azar, así que ten en cuenta que los tiempos fluctuarán.

$a = array();
for ($i = 0; $i < 10000; ++$i) {
    $v = rand(1, 1000000);
    $a[$v] = $v;
}
echo "Size: ", count($a), PHP_EOL;

$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    isset($a[rand(1, 1000000)]);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;

$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    in_array(rand(1, 1000000), $a);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;

93
2017-11-20 22:48



Cual es mas rápido: isset() vs in_array()

isset() es más rápido.

Si bien debería ser obvio, isset() solo prueba un solo valor. Mientras in_array() iterará sobre toda la matriz, probando el valor de cada elemento.

La evaluación comparativa aproximada es bastante fácil de usar microtime().

Resultados:

Total time isset():    0.002857
Total time in_array(): 0.017103

Nota: Los resultados fueron similares independientemente de si existió o no.

Código:

<?php
$a = array();
$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    isset($a['key']);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;

$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    in_array('key', $a);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;

exit;

Recursos adicionales

Te animo a que también mires:


34
2017-11-20 22:27



Utilizando isset() aprovecha una búsqueda más rápida porque usa una tabla de picadillo, evitando la necesidad de O(n) búsquedas.

La clave es hash primero usando el función hash djb para determinar el cubo de claves hash similares en O(1). El cubo se busca iterativamente hasta que se encuentre la clave exacta en O(n).

Exceptuando cualquier colisiones hash intencionales, este enfoque produce un rendimiento mucho mejor que in_array().

Tenga en cuenta que al usar isset() en la forma que has mostrado, pasar los valores finales a otra función requiere el uso de array_keys() para crear una nueva matriz Se puede hacer un compromiso de memoria almacenando los datos tanto en las claves como en los valores.

Actualizar

Una buena manera de ver cómo las decisiones de diseño de código afectan el rendimiento del tiempo de ejecución, puede consultar versión compilada de tu script:

echo isset($arr[123])

compiled vars:  !0 = $arr
line     # *  op                           fetch      ext  return  operands
-----------------------------------------------------------------------------
   1     0  >   ZEND_ISSET_ISEMPTY_DIM_OBJ              2000000  ~0      !0, 123
         1      ECHO                                                 ~0
         2    > RETURN                                               null

echo in_array(123, $arr)

compiled vars:  !0 = $arr
line     # *  op                           fetch      ext  return  operands
-----------------------------------------------------------------------------
   1     0  >   SEND_VAL                                             123
         1      SEND_VAR                                             !0
         2      DO_FCALL                                 2  $0      'in_array'
         3      ECHO                                                 $0
         4    > RETURN                                               null

No solo lo hace in_array() utilizar un relativamente ineficiente O(n) búsqueda, también debe llamarse como una función (DO_FCALL) Considerando isset() usa un solo código de operación (ZEND_ISSET_ISEMPTY_DIM_OBJ) para esto.


16
2017-11-20 23:09



El segundo sería más rápido, ya que solo busca esa clave de matriz específica y no necesita iterar en toda la matriz hasta que se encuentre (verá todos los elementos de la matriz si no se encuentra)


6
2017-11-20 22:22