这个问题仅供我使用,因为我总是喜欢编写优化的代码,这些代码也可以在便宜的慢速服务器(或具有大量流量的服务器)上运行
我环顾四周,无法找到答案。我想知道这两个例子之间的速度有多快,记住我的情况下数组的键并不重要(伪代码自然):<?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)
答案 0 :(得分:106)
到目前为止,答案是现实的。在这种情况下使用isset
会更快,因为
in_array
必须检查每个值,直到找到匹配为止。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;
答案 1 :(得分:38)
哪个更快:
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;
我鼓励你也看看:
答案 2 :(得分:17)
使用isset()
可以利用更快的查询速度,因为它使用hash table,无需进行O(n)
次搜索。
首先使用djb hash function对密钥进行哈希处理,以确定O(1)
中类似哈希密钥的存储桶。然后迭代搜索存储桶,直到在O(n)
中找到确切的密钥。
除了in_array()
之外,这种方法的效果要比isset()
好得多。
请注意,以您显示的方式使用array_keys()
时,将最终值传递给另一个函数需要使用echo isset($arr[123])
来创建新数组。通过将数据存储在键和值中,可以实现内存泄露。
<强>更新强>
了解代码设计决策如何影响运行时性能的好方法,您可以查看脚本的intentional hash collisions:
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
使用单个操作码({ {1}})为此。
答案 3 :(得分:6)
第二个会更快,因为它只查找特定的数组键,并且不需要遍历整个数组,直到找到它(如果找不到,将查看每个数组元素)