Что быстрее: 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)
Ответы
Ответ 1
Ответы до сих пор находятся на месте. Использование 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;
Ответ 2
Это быстрее: 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;
Дополнительные ресурсы
Я бы посоветовал вам также посмотреть:
Ответ 3
Использование isset()
использует более быстрый поиск, потому что он использует таблицу хешей , избегая необходимости поиска O(n)
.
Ключ сначала хэшируется с помощью функции хеша djb, чтобы определить ведро аналогичных хэшированных клавиш в O(1)
. Затем ведро выполняется итеративно до тех пор, пока точный ключ не будет найден в O(n)
.
Запрет любых преднамеренных хеш-коллизий, этот подход дает гораздо лучшую производительность, чем in_array()
.
Обратите внимание, что при использовании isset()
в том виде, который вы указали, передача конечных значений другой функции требует использования array_keys()
для создания нового массива. Компромисс памяти может быть сделан путем хранения данных как в ключах, так и в значениях.
Обновление
Хороший способ увидеть, как ваши решения по дизайну кода влияют на производительность выполнения, вы можете проверить скомпилированную версию вашего 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
Не только in_array()
использует относительно неэффективный поиск O(n)
, он также должен быть вызван как функция (DO_FCALL
), тогда как isset()
использует один код операции (ZEND_ISSET_ISEMPTY_DIM_OBJ
) для этого.
Ответ 4
Второй будет быстрее, поскольку он ищет только этот конкретный массив ключей и не нуждается в повторении по всему массиву до его обнаружения (будет выглядеть каждый элемент массива, если он не найден)