c++ - 为什么程序启动缓慢但后来获得全速?

标签 c++ performance

我注意到有时程序运行很慢,但后来性能很好。例如,我有一些循环运行的代码,第一次迭代需要很长时间,但相同代码的其他迭代运行得非常快。很难说出具体情况,因为我无法弄清楚,而且似乎即使是单个文字也会影响这种行为。我准备了一个小代码片段:

#include <chrono>
#include <vector>
#include <iostream>

using namespace std;

int main()
{
    const int num{ 100000 };

    vector<vector<int>> octs;
    for (int i{ 0 }; i < num; ++i)
    {
        octs.emplace_back(vector<int>{ 42 });
    }

    vector<int> datas;
    for (int i{ 0 }; i < num; ++i)
    {
        datas.push_back(42);
    }

    for (int n{ 0 }; n < 10; ++n)
    {
        cout << "start" << '\n';
        //cout << 0 << "start" << '\n';

        auto start = chrono::high_resolution_clock::now();

        for (int i{ 0 }; i < num; ++i)
        {
            vector<int> points{ 42 };
        }

        auto end = chrono::high_resolution_clock::now();
        auto time = chrono::duration_cast<chrono::milliseconds>(end - start);

        cout << time.count() << '\n';
    }

    cin.get();

    return 0;
}

前两个 vector 是必不可少的。至少在 Visual Studio 中。以为它们没有被使用,它们会对性能产生很大影响。此外,调整它们也会产生性能影响(例如更改初始化顺序,删除 push_back 并在构造函数中分配必要的大小)。但是这段代码给了我以下结果:

  • 使用 gcc 完全没有问题
  • 使用 clang 时,第一次迭代的时间是其他迭代的两倍
  • 对于 vs2013,第一次迭代要慢 100(是的,一百)倍。

此外,对于 vs2013,如果我取消注释行 cout << 0 << "start" << '\n';性能问题消失了,所有迭代都是平等的!

这是怎么回事?

最佳答案

对于前两个循环,最大的性能考虑可能是内存分配,以及将 vector 内容复制到更大的缓冲区。在这种情况下,循环似乎“加速”这一事实并不奇怪。

这是由于 vector 类的实现细节所致。让我们看看documentation :

Internally, vectors use a dynamically allocated array to store their elements. This array may need to be reallocated in order to grow in size when new elements are inserted, which implies allocating a new array and moving all elements to it. This is a relatively expensive task in terms of processing time, and thus, vectors do not reallocate each time an element is added to the container.

Instead, vector containers may allocate some extra storage to accommodate for possible growth, and thus the container may have an actual capacity greater than the storage strictly needed to contain its elements (i.e., its size). Libraries can implement different strategies for growth to balance between memory usage and reallocations, but in any case, reallocations should only happen at logarithmically growing intervals of size so that the insertion of individual elements at the end of the vector can be provided with amortized constant time complexity (see push_back).

所以在幕后,为您的 vector 分配的实际内存可能比您实际使用的要多得多。因此,当您向 vector 添加一个不适合其当前缓冲区的新元素时,vector 只需要进行代价高昂的重新分配和复制。此外,由于它表示重新分配应该只以对数增长的间隔发生,您可以预期 vector 类在每次需要重新分配时都会将缓冲区大小大致加倍。但请注意,各种平台上的 vector 实现都经过高度调整,以针对该类的最常见使用模式进行优化,这可能是您在工具链和平台上看到的不同性能的一个因素。

所以你应该看到循环在前几次执行时很慢,然后随着 push_backemplace 操作需要做更少的重新分配和复制而获得更快的速度以适应新元素。

所以我认为这是您可以用来推断执行前两个循环需要多长时间的主要事实。但是对于您的具体示例,由于程序的简单性,编译器可能会对其生成的代码采取一些自由。所以我们可以想象,一个足够聪明的优化编译器可能能够看到您的 vector 只会增长到它在编译时知道的大小,num。这是我怀疑你最后一个循环的最大问题,这似乎是一个任意且无用的测试。例如,循环 3 中的嵌套循环可以完全优化掉。我认为这是您在不同编译器中看到如此不同的运行时行为的主要原因。

如果您想了解真实情况,请查看您的编译器生成的汇编代码。

关于c++ - 为什么程序启动缓慢但后来获得全速?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38482007/

相关文章:

c - Blit 比条件 + 指针增量更快?

java - 模式搜索性能差

c++ - 在 CodeLite 中链接 SFML

Java 似乎比 C++ 更快地执行基本算法。为什么?

c++ - 保留硬盘中数据的物理地址

mysql - 如何测试查询的实际执行时间?

php - MySql "Preparing"花费太多时间

c++ - 使用 CryptoAPI 导出为 PEM 格式

c++ - XSD : value not in enumeration

c# - 如何以 MHz 为单位快照处理器各个内核的速度