【发布时间】:2013-05-16 13:25:48
【问题描述】:
在一个非常紧凑的循环中,我需要访问包含数百万个元素的数组中的数万个值。键可以是未定义的:在这种情况下,返回 NULL 而没有任何错误消息是合法的:
数组键存在:元素的返回值。 数组键不存在:返回 null。
我确实知道多种解决方案:
if (isset($lookup_table[$key])) {
return $lookup_table[$key];
} else {
return;
}
或
@return $lookup_table[$key];
或
error_reporting(0);
$return = $lookup_table[$key];
error_reporting(E_ALL);
return $return;
所有解决方案都远非最佳:
- 第一个需要在 B-TREE 中进行 2 次查找:一个用于检查存在,另一个用于检索值。这实际上使运行时间加倍。
- 第二个使用错误抑制运算符,因此会在该行上产生大量开销。
- 第三个调用错误处理程序(它将检查 error_reporting 设置,然后什么也不显示),从而产生开销。
我的问题是我是否错过了一种避免错误处理但仍使用单个 Btree 查找的方法?
回答一些问题:
该数组缓存了复杂计算的结果——要实时完成复杂。 在数十亿个可能的值中,只有数百万个产生有效结果。该数组看起来像 1234567 => 23457, 1234999 => 74361, ...。它被保存到一个几兆字节的 PHP 文件中,并在执行开始时 include_once-d。初始加载时间无关紧要。 如果未找到该键,则仅表示此特定值不会返回有效结果。问题是每秒完成 50k+。
结论
由于无法通过单次查找和错误处理来获取值,因此我无法接受单个答案。相反,我对所有伟大的贡献投了赞成票。
最有价值的输入:
- 使用 array_key_exists,因为它比其他方法更快
- 查看 PHP 的 QuickHash
关于 PHP 如何处理数组存在很多困惑。如果你查看源代码,你会发现所有的数组都是平衡树。构建自己的查找方法在 C 和 C++ 中很常见,但在 PHP 等高级脚本语言中性能不佳。
【问题讨论】:
-
isset($lookup_table[$key])将返回false如果$lookup_table[$key]是null...这不是你想要的相反吗?不确定它的性能如何,但如果键存在但其值为null,array_key_exists将返回true。 -
@sgroves:这个例子确实反映了我的意图。我更新了问题以澄清:如果键存在,则返回值,否则返回null。 (现有键的值永远不会为空。)坦率地说,array_key_exist 比 isset 版本慢,所以我在示例中跳过了它。
-
Quickhash 可能适合您的情况。
-
“一个包含数百万个元素的数组”。您可能需要重新考虑您的策略,并涉及某种类型的分页或数据细分方式。
-
迈克,马修,我更新了我的问题来回答你的问题。肖恩,这不是相信的问题。当然,原生 C 比 PHP 更快。我根本不愿意花一个月的时间来写我可以用 PHP 写一整夜的代码。 :)
标签: php performance