PHP for循环与C for循环

时间:2013-12-28 22:27:05

标签: php c++ performance for-loop

众所周知,在PHP中执行以下操作是个坏主意(因为每次迭代都会调用count ($array),这会严重降低脚本执行速度):

<?php
for ( $i = 0; $i < count ($array); ++$i )
{
   // Code here;
}

相反,应该在循环之外计算条件:

<?php
$a = count ($array);

for ( $i = 0; $i < $a; ++$i )
{
   // Code here;
}

我是编译语言的新手,所以我有一个问题:

例如,同样的规则适用于C和C ++等编译语言吗?

假设我想在C ++中迭代向量。我应该避免这样的循环还是没问题?

for ( int i = 0; i < vector.size(); ++i )
{
    // Code here
}

如果这在编译语言中不是问题 - 是因为编译器会照顾它并优化可执行文件,或者还有其他原因吗?

3 个答案:

答案 0 :(得分:2)

排序,for循环可以在C ++中解释如下:

{
    int i = 0; // initializer
    while(i < vector.size()){
         // loop body
         ++i; // increment
    }
}

所以size被称为每个增量,它不是很重

由于您正在使用vector,更好的方法是使用迭代器来保证安全:

for(auto iter = vector.begin(), end = vector.end(); iter != end; ++iter)
{
}

请注意,我在初始化时只初始化迭代器一次而不是与.end()进行比较,这对于某些容器类型来说可能很昂贵,尽管vector与调用{size没什么不同。 1}}就效果而言。

或新的C ++ 11循环

for(auto & i: vector){
}

这实际上只是上面的迭代器示例的语法糖

老实说 C ++担心微观优化......应该避免使用可读性。与解释型语言不同,编译器可以做很多事情来解决小的性能错误。在微软的STL维护者的(转述)字眼“不要'帮助'编译器,你会让事情变得更糟”

答案 1 :(得分:1)

问题归结为“编译器是否在编译时知道答案”?

在你给出的情况下,答案是“不”。由于可以在循环中更改向量的大小,因此每次都应该对其进行评估(但它非常快,因为它一次不计算一个)。

这样的代码:

int myArray[20];
for(int ii = 0; ii < sizeof(myArray)/sizeof(*myArray); ii++) {
事实上,

会在编译时评估sizeof,因此会更有效率。注意 - 您需要整个表达式,因为在这种情况下sizeof(myArray)本身将返回80(其中int是四个字节)。使用sizeof(*myArray)的好处是,如果您改变对myArray类型的看法,这行代码就不会中断...

你在这里使用除法的事实并没有减慢执行速度,因为它都是在编译期间完成的(只有一次)。

重新迭代我在评论中所说的内容:在这个例子中,你提出的版本,同时在每次迭代时评估向量的大小,实际上不是问题。除了最严格的循环外,你几乎不可能看到性能差异。不要落入the trap of micro-optimization

这是一个简单的计时示例:

#include <iostream>
#include <ctime>
#include <vector>

using namespace std;

int main(void) {
  vector<int> testVector(200);
  int ii, jj;
  register int ss;
  time_t startT, endT;

  // case 1: using a constant for loop condition
  startT = clock();
  for(ii = 0; ii < 100000; ii++) {
    for(jj = 0; jj < 200; jj++) {
      testVector[jj] = ii - jj;
    }
  }
  endT = clock();
  printf("using constant: elapsed time: %.2f ms\n", (endT - startT) * 1000.0 / CLOCKS_PER_SEC);

  // case 2: using size():
  startT = clock();
  for(ii = 0; ii < 100000; ii++) {
    for(jj = 0; jj < testVector.size(); jj++) {
      testVector[jj] = ii - jj;
    }
  }
  endT = clock();
  printf("using size: elapsed time: %.2f ms\n", (endT - startT) * 1000.0 / CLOCKS_PER_SEC);

  // case 3: single call to size():
  startT = clock();
  ss = testVector.size();
  for(ii = 0; ii < 100000; ii++) {
    for(jj = 0; jj < ss; jj++) {
      testVector[jj] = ii - jj;
    }
  }
  endT = clock();
  printf("with size out of loop: elapsed time: %.2f ms\n", (endT - startT) * 1000.0 / CLOCKS_PER_SEC);
}

这给出了以下结果:

using constant: elapsed time: 162.47 ms
using size: elapsed time: 277.02 ms
with size out of loop: elapsed time: 241.01 ms

正如您所看到的, 与在每个循环中查找向量大小相关的有限时间;但是对于20,000,000个呼叫大约需要100毫秒,或者每个呼叫大约需要5毫秒。这听起来是正确的;正如你所看到的,当你的循环足够紧密时,它是可测量的;但它在大多数“真正的”代码实例中都不太可能具有实际意义(在循环中你可能会做更多的事情)。正如您所看到的,只是将调用移动到size的循环doest有很大帮助 - 使用常量vs变量是一个更大的区别。

答案 2 :(得分:1)

它是一样的。编译器或解释器无法知道整个循环中是否会改变大小。

但是,如果你知道你不会改变大小 - 你肯定可以在循环外计算变量,就像在PHP中一样。