что быстрее: in_array или isset?

Этот вопрос просто для меня, поскольку мне всегда нравится писать оптимизированный код, который может работать и на дешевых медленных серверах (или на серверах с большим количеством трафика)

Я огляделся, и я не смог найти ответа. Мне было интересно, что быстрее между этими двумя примерами, имея в виду, что ключи массива в моем случае не важны (естественно, псевдокод):

<?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 } } ?> 

Поскольку точкой вопроса является не столкновение массива, я хотел бы добавить, что если вы боитесь встречных вставок для $a[$new_value] , вы можете использовать $a[md5($new_value)] . он все равно может вызвать конфликты, но может уйти от возможной атаки DoS при чтении из предоставленного пользователем файла ( http://nikic.github.com/2011/12/28/Supercolliding-a-PHP-array.html )

Ответы до сих пор находятся на месте. Использование isset в этом случае происходит быстрее, потому что

  • Он использует поиск хэша O (1) на ключе, тогда как in_array должен проверять каждое значение, пока не найдет совпадение.
  • Будучи кодом операции, он имеет меньше накладных расходов, чем вызов встроенной функции in_array .

Их можно продемонстрировать, используя массив со значениями (10000 в приведенном ниже тесте), заставляя in_array выполнять больше поиска.

 isset: 0.009623 in_array: 1.738441 

Это основывается на контрольном показателе Джейсона, заполняя некоторые случайные значения и время от времени обнаруживая значение, существующее в массиве. Все случайные, поэтому будьте осторожны, что времена будут колебаться.

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

Что быстрее: isset() vs in_array()

isset() работает быстрее.

Хотя это должно быть очевидно, isset() проверяет только одно значение. В то время как in_array() будет перебирать весь массив, проверяя значение каждого элемента.

Простой бенчмаркинг довольно просто с использованием microtime() .

Результаты:

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

Примечание. Результаты были одинаковыми независимо от того, существовали они или нет.

Код:

 <?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; 

Дополнительные ресурсы

Я бы посоветовал вам также посмотреть:

  • PHP Benchmark
  • PHPPerf
  • XDebug

Использование isset() использует быстрый поиск, потому что он использует хеш-таблицу , избегая необходимости поиска O(n) .

Ключ сначала хэширует, используя хэш-функцию djb, чтобы определить ведро аналогично хэшированных клавиш в O(1) . Затем ведро выполняется итеративно до тех пор, пока не будет найден точный ключ в O(n) .

Запрещая любые преднамеренные хеш-коллизии , этот подход дает гораздо лучшую производительность, чем in_array() .

Обратите внимание, что при использовании isset() в том виде, в котором вы показывали, передача конечных значений другой функции требует использования array_keys() для создания нового массива. Компромисс памяти может быть сделан путем хранения данных как в ключах, так и в значениях.

Обновить

Хороший способ увидеть, как ваши решения по дизайну кода влияют на производительность выполнения, вы можете проверить скомпилированную версию вашего скрипта:

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 

Мало того, что in_array() использует относительно неэффективный O(n) поиск, его также нужно вызывать как функцию ( DO_FCALL ), тогда как isset() использует для этого один код операции ( ZEND_ISSET_ISEMPTY_DIM_OBJ ).

Второй будет быстрее, поскольку он ищет только этот конкретный массив ключей и не нуждается в повторении по всему массиву до его обнаружения (будет рассмотрен каждый элемент массива, если он не найден)