【发布时间】:2018-06-30 23:33:22
【问题描述】:
出于好奇,我试图了解 array_merge 和 union 如何在 PHP 的幕后工作。
有人可以帮我了解 ZEND 幕后的内部结构吗:
-
array_merge(在 CPU 和 RAM 上较慢) -
UNION(各方面更快)
这是我正在运行的基准代码:https://gist.github.com/EnchanterIO/6e90f828c1b32c894d35267c353e83d2
使用 PHP 7 的输出是:
➜ ArrayMerge git:(master) ✗ php src/benchmark.php array_merge 20000
使用 array_merge 构建包含 20000 个元素的数组需要 7 秒。
内存使用量为:8 MB。内存峰值为:12288 MB。
➜ ArrayMerge git:(master) ✗ php src/benchmark.php union 20000
使用 union 构建包含 20000 个元素的数组耗时 0 秒。
内存使用量为:8 MB。内存峰值为:10240 MB。
我对 array_merge 的理论:
我正在查看PHP source code written in C for array merge(如果这甚至是正确的地方),尽管它对我来说有点难以理解,因为我不熟悉行话,这似乎是array_merge 速度较慢的原因是由于需要额外的 foreach 以及 array_merge 对结果数组中的数字键重新编号。
我对 UNION 的理论:
没有找到它的源代码,但据我所知,向数组添加元素的工作方式如下:
- 一开始,数组内部分配了一些内存
- 通过向数组添加新元素,最终数组需要在后台动态分配更多内存,因此 PHP 内部 (C) 会创建一个具有双倍内存量的新数组并复制内容
- 通过添加更多元素重复此过程
- 没有重新排序,没有 foreach,只是随着时间的推移增加内存
谁能更深入地了解这个过程并深入解释 ZEND 魔法的幕后故事?
更新:
我被提及以下链接,但仍然无法理解它:
https://lxr.room11.org/xref/php-src%40master/Zend/zend_opcode.c#740 https://lxr.room11.org/xref/php-src%40master/Zend/zend_operators.c#897 https://lxr.room11.org/xref/php-src%40master/Zend/zend_hash.c#1915
【问题讨论】:
-
您比较的两个代码做的事情不同。特别是,
$list[] = [$i => [$i]]应该是$list[$i] = [$i]还是$list[] = [$i]? -
您在基准代码中的哪个位置应用了数组联合?
-
@NikiC 啊...你是对的!!!我非常专注于 PHP 内部,不知怎么地忽略了这个错误。这就解释了当我创建一个索引太高 ($i) 而不是索引为 0 的数组时需要双倍内存!好的,内存错误已修复。现在它是有道理的。我对 UNION 的理论是正确的吗?你会在数组合并部分添加一些额外的解释吗?我添加了一些可能有用的 ZEND 链接。 Revo 你会怎么称呼:“list[$i] = [$i]”?
-
@EnchanterIO array_merge 和 []= 之间的相关区别是 array_merge 复制数组而 []= 不复制(除非需要增加容量)。这就是为什么 array_merge 是 O(n) 而 []= 是(摊销) O(1)。循环运行,这就是 O(n^2) 和 O(n) 的区别。到那时,具体的实现细节就不再重要了。
-
实际上经过进一步检查后,我意识到我之前的基准测试具有误导性,并且在@NikiC 的某些现实生活场景中几乎没有使用过。请检查我的答案,了解更多详细信息和第二个基准 Niki。
标签: php performance memory cpu internals