【问题标题】:What is the difference between while(true) and for(;;) in PHP?PHP 中的 while(true) 和 for(;;) 有什么区别?
【发布时间】:2014-05-19 21:41:37
【问题描述】:

除了语法和可读性之外,while(true)for(;;) 之间的 PHP 有什么区别吗?

【问题讨论】:

  • @Touchpad 我很想知道特定于 PHP 的答案
  • codepad.viper-7.com/awq3Mh 通常我看到while(true) 的性能稍快
  • @AzizSaleh 所以 PHP 被编译成 C++ 然后执行?我虽然 PHP 是用 C 编写并编译成它自己的字节码。
  • 如果你想少写,你可以用while(1)
  • 为什么它被搁置为基于意见?也许如果问题询问可读性,但它明确排除了这一点。疯了。

标签: php for-loop while-loop infinite-loop php-internals


【解决方案1】:

好的,首先,让我这样说:使用while(true),因为它提供了最多的语义含义。您需要解析 for (;;),因为它不是您经常看到的。

说了这么多,我们来分析一下:

操作码

代码

while(true) {
    break;
}
echo "hi!";

编译成操作码:

0: JMPZ(true, 3)
1: BRK(1, 3)
2: JMP(0)
3: ECHO("hi!")

所以基本上,它会检查是否为“真”,如果不是,则跳转到第四个操作码,即回显操作码)。然后它会中断(这实际上只是到第四个操作码的静态跳转)。那么循环的结束就是无条件跳回原来的检查

比较一下:

for (;;) {
    break;
}
echo "hi!";

编译为:

0: JMPZNZ(true, 2, 4)
1: JMP(0)
2: BRK(1, 4)
3: JMP(1)
4: ECHO("hi!")

所以我们可以立即看到for(;;) 版本中有一个额外的操作码。

操作码定义

JMPZ(条件,位置)

如果条件为false,则此操作码会跳转。如果是true,它只会前进一个操作码。

JMPZNZ(条件, pos1, pos2)

如果条件为真,此操作码跳转到pos1,如果条件为假,则跳转到pos2

JMP(位置)

这个操作码总是跳转到指定位置的操作码。

BRK(级别,位置)

这会将level 级别打破为position 处的操作码

回声(字符串)

输出字符串

他们是一样的

好吧,看看操作码,很明显它们并不相同。他们是==,但不是===while(true) 循环执行条件跳转,然后是代码,然后是无条件跳转。 for(;;) 循环执行条件跳转,然后是代码,然后是无条件跳转,然后是另一个无条件跳转。所以它做了一个额外的跳跃。

Opcache

在 5.5 中,opcache 的优化器部分将 optimize static conditional jumps

这意味着while(true) 代码将优化为:

0: BRK(1, 2)
1: JMP(0)
2: ECHO("hi!")

for(;;) 循环变为:

0: BRK(1, 2)
1: JMP(0)
2: ECHO("hi!")

这是因为优化器会找到并优化出跳转链。因此,如果您使用 5.5 的内置 opcache,它们将是相同的......

注意

这是一个完整而彻底的微优化,可作为决策依据。使用可读的。不要基于性能使用一个。区别是存在的,但微不足道。

【讨论】:

  • JMP(1) 作为优化后的while 版本中的第一条指令有什么意义?这不是有效的无操作吗?为什么它没有得到优化?
  • @bdesham:它似乎确实得到了优化:lxr.php.net/xref/PHP_TRUNK/ext/opcache/Optimizer/pass3.c#134 它看起来也像 JMP(2); JMP(0); 将优化到 JMP(2);,但我不能立即判断它是否会被优化进一步到 NOP...
  • 出色的分析!相同的行为导致相同的优化(理想情况下应该如此),并且更语义化的构造具有更少的操作码预优化,使其成为此类微优化的“更好”选择,强化了while(true)应该是首选的事实.
  • "使用 while(true),因为它提供了最多的语义含义。您需要解析 (;;),因为它不是您经常看到的东西。"就个人而言,我将(;;) 解析为一张哭脸,因为你为什么要写无限循环?这让我很难过。
  • @mikeTheLiar 从技术上讲,任何事件循环都是一个简单的无限循环轮询输入。至于“你需要解析for (;;)”部分——它实际上经常用在C 而不是while (1) 中,因为linter 对for 变体的抱怨较少[需要引用]跨度>
猜你喜欢
  • 2011-01-16
  • 1970-01-01
  • 2023-03-14
  • 2011-03-21
  • 1970-01-01
  • 2020-11-06
  • 2018-12-20
  • 2019-10-07
相关资源
最近更新 更多