[php] 더 빠른 것 : 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)]. 여전히 충돌을 일으킬 수 있지만 사용자가 제공 한 파일 ( http://nikic.github.com/2011/12/28/Supercolliding-a-PHP-array.html ) 에서 읽을 때 가능한 DoS 공격을 피할 수 있습니다.



답변

지금까지의 답변은 정확합니다. isset이 경우 사용 하는 것이 더 빠릅니다.

  • 키에서 O (1) 해시 검색을 사용하는 반면 in_array일치 항목을 찾을 때까지 모든 값을 확인해야합니다.
  • opcode이므로 in_array내장 함수를 호출하는 것보다 오버 헤드가 적습니다 .

값이있는 배열 (아래 테스트에서 10,000 개)을 사용하여 in_array더 많은 검색을 수행 함으로써 이를 입증 할 수 있습니다 .

isset:    0.009623
in_array: 1.738441

이것은 임의의 값을 채우고 때때로 배열에 존재하는 값을 찾아 Jason의 벤치 마크를 기반으로합니다. 모두 무작위이므로 시간이 변동될 수 있습니다.

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

추가 자료

다음 사항도 살펴 보시기 바랍니다.


답변

를 사용하면 해시 테이블을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)검색을 사용할 뿐만 아니라 이를 위해 단일 opcode ( )를 사용하는 DO_FCALL반면 함수 ( ) 로 호출해야합니다 .isset()ZEND_ISSET_ISEMPTY_DIM_OBJ


답변

두 번째는 특정 배열 키만 찾고 발견 될 때까지 전체 배열을 반복 할 필요가 없기 때문에 더 빠릅니다 (찾을 수없는 경우 모든 배열 요소를 봅니다).


답변