이 질문은 내가 항상 값싼 느린 서버 (또는 트래픽이 많은 서버)에서도 실행할 수있는 최적화 된 코드를 작성하는 것을 좋아하기 때문에 나에게만 해당됩니다.
주위를 둘러 보니 답을 찾을 수 없었습니다. 필자의 경우 배열의 키가 중요하지 않다는 점을 염두에두고이 두 예제 사이에서 무엇이 더 빠른지 궁금합니다 (당연히 의사 코드).
<?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
답변
두 번째는 특정 배열 키만 찾고 발견 될 때까지 전체 배열을 반복 할 필요가 없기 때문에 더 빠릅니다 (찾을 수없는 경우 모든 배열 요소를 봅니다).