C++ 打印进度,对运行时的影响最小

C++ print progress with minimal impact on runtime

我有一个带有长 运行 循环的 C++ 程序。它有大约 500000 次迭代。 我想每 5% 打印一次进度。

目前我所拥有的如下。 问题是它会一遍又一遍地写同一行(0%、%5 等)。这是因为在将百分比截断为整数后,有 1000 次迭代将命中 5 的倍数。这使得程序明显变慢。

相反,如果我不截断为整数,那么 percent % 5.0 的结果不太可能恰好为 0。

如何在对运行时影响最小的情况下打印进度指示器?

// Counters for progress indicator
int i = 0;
float totalWindows = (float)(win.nX * win.nY);
int percent;

while (win.next() == 0)
{
    // Read the data

    // Nicely formatted progress indicator
    i++;
    percent = (i / totalWindows) * 100;
    if (percent % 5 == 0)
    {
        std::cout << "\r" << std::string(percent/5, '|') << percent << "%";
        std::cout.flush();
    }



}

编辑: 感谢您的回答。我选择了 christophes',它的指令数量最少。 它节省了 25% 的运行时间,非常重要!

怎么样:

int step = 5;
int nextPrint = step;

while (win.next() == 0)
{
    // Read the data

    // Nicely formatted progress indicator
    i++;
    percent = (100 * i) / totalWindows;
    if (percent >= nextPrint)
    {
        std::cout << "\r" << std::string(percent/5, '|') << percent << "%";
        std::cout.flush();
        nextPrint += step;
    }
}

顺便说一句: 为什么将 totalWindows 作为浮点数?这也会损害性能。如果迭代次数为 500000,则 32 位 int 应该足够了。

另一种更好的方法,因为并不是在每个循环中都计算百分比:

const int percentPrint = 5;
int step = totalWindows / (100/percentPrint);
int nextPrint = step;

while (win.next() == 0)
{
    // Read the data

    // Nicely formatted progress indicator
    i++;
    if (i >= nextPrint)
    {
        percent = (100 * i) / totalWindows;
        std::cout << "\r" << std::string(percent/percentPrint , '|') << percent << "%";
        std::cout.flush();
        nextPrint += step;
    }
}
std::cout << "\r" << std::string(100/percentPrint , '|') << percent << "%";
std::cout.flush();

不用每次都计算百分比,你可以算出总数的5%是多少,直接用这个

考虑这个简化的例子:

int main(int argc, char * argv) {
  int total = 50000;
  int total_percent_stop = total * 5 / 100; //Set the percentage here.

  for (int i = 0; i < total; i++) {
    if (i % total_percent_stop == 0) {
      printf("%d percent done\n", (i / total_percent_stop) * 5);
    }
  }
}

如果这个特定代码的性能对你来说非常重要,你可以通过这样做来避免相对昂贵的除法运算(以牺牲一些可读性为代价)。

int main(int argc, char * argv) {
  int total = 50000;
  int total_percent_stop = total * 5 / 100; //Set the percentage here

  for (int i = 0, percent_counter = 0, n_percent = 0;
       i < total;
       i++, percent_counter++) {
    if (percent_counter == total_percent_stop) {
      percent_counter = 0;
      n_percent++;
      printf("%d percent done\n", n_percent * 5);
    }
  }
}

在我的机器上,对于足够大的总值,第二个要快得多。当我将所有内容更改为 unsigned long longs 并将总数设置为 50 亿时,第二个用了 9.336 秒,第一个用了 40.159 秒

考虑到 totalWindows 似乎保持不变,并且 integer increments/decrements 可能会比许多转换为 int 的 double 操作更快,我建议:

// Counters for progress indicator
int i = 0;
float totalWindows = (float)(win.nX * win.nY);
int increment5 = 0.05 * totalWindows; // how many iterations does 5% represent ? 
int countdown = increment5;   // decrement countdown instead of modulo
int percent5 = 0;  // number of elements in the progress bar (1 means 5%)

while (win.next() == 0)
{
    // Read the data

    // Nicely formatted progress indicator
    i++;
    if (--countdown == 0)
    {
            percent5++;
            std::cout << "\r" << std::string(percent5, '|') << percent5*5 << "%";
            countdown = increment5;  
            std::cout.flush();
    }

}

如果您担心累积舍入不能用于显示进度,您始终可以选择在 if 块中计算精确值:计算将只每 5% 执行一次在每次迭代中。