【问题标题】:C++ code executes slow [closed]C ++代码执行缓慢[关闭]
【发布时间】:2013-01-25 14:02:13
【问题描述】:

上周我将递归 Branch&Cut 算法从 Matlab 移植到 C++,并希望看到求解时间显着减少,但尽管听起来令人难以置信,但事实恰恰相反。 现在我并不是真正的 C++ 专家,所以我下载了 sleepy profiler 并试图找到潜在的瓶颈。我想问一下我是否从中得出了正确的结论,或者我是否正在寻找一个完全错误的方向。

我让代码运行了 137 秒,这就是分析器显示的内容(下面还有许多其他条目,但它们无关紧要):

如果我做对了,98 秒用于创建新对象,34 秒用于释放内存(即删除对象)。

我会检查我的代码,看看哪里可以做得更好,但我也想问你是否有任何关于导致此类行为的常见错误或不良习惯的提示。我想到的一件事是我在代码中使用了很多临时的 std::vectors 来计算东西,所以这可能会很慢。

为了避免你失明,我不会在我仔细研究之前发布我的代码,但如果我不能自己解决这个问题,我会回来的。

【问题讨论】:

  • 这不是一个真正的问题。没有看到代码就无法说出发生了什么。但一般来说,新手 C++ 程序员经常编写慢程序,因为他们不了解 C++ 的值语义和复制构造函数语义。您需要尽可能使用引用或移动语义以避免不必要的向量/字符串复制,以及vector::reserve 以减少重新分配的数量。
  • 我对 C++ 还有些陌生,但我认为在堆栈上分配临时空间会有很大帮助。
  • 您在分析调试版本吗?您应该对所有优化进行分析。
  • 这是一个发布版本,Visual Studio 设置为“完全优化”,所以我担心这是我的代码的问题。但是感谢您的 cmets,我看到我在正确的轨道上!
  • 如何在函数之间传递向量(尤其是大向量)?通过值:void function(vector a),通过引用:void function(vector &a) 或通过指针:void function(vector *a) 分别。 void function(shared_ptr<vector> a) ?

标签: c++ performance profiler


【解决方案1】:

是的,std::vectors 如果使用不当可能会很昂贵。最大的性能损失可能是重新分配 - 因为大小需要动态调整,并且元素必须在连续内存中,所以每当您添加超出已分配内容的新元素时,就会发生重新分配。

这就是为什么您应该事先声明尺寸。如果您知道必须持有 n 元素,请将其声明为

 std::vector<MyClass> x(n);

 std::vector<MyClass> x;
 x.reserve(n);

而不仅仅是

 std::vector<MyClass> x;

后跟n push_backs。

如果在此之后仍然很慢,您可以为std::vector 提供自定义分配器。我希望你不要到那个地步。

【讨论】:

  • 我事先声明了尺寸,所以这是我避免的一些陷阱:)
  • 如果自动调整大小总是使容量加倍,则在向量大小 M 处,最多执行了 2M 个副本(以及最多 log2(M) 次重新分配),在任何合理的初始容量下要少得多。在任何乘数 B 处,任何向量大小的副本/元素最多为 B/{B-1},因此在 1.5 倍时最多为 3,在 1.25 倍时最多为 5。除非副本非常昂贵,否则这在噪音,不值得担心。
【解决方案2】:

在 Matlab 中,一切都是对对象的引用。因此,当您传递它们时,您相当于复制了一个指针(大小约为 int,具体取决于几个因素),而不是复制整个矩阵,这可能更大。

没有看到任何代码,我不能肯定地说,但我怀疑您正在复制大量对象而不是复制对它们的引用。我建议你看看智能指针,比如std::shared_ptr

你没有说清楚,但你应该优化编译。 (g++ -O3.) 可以优化一些昂贵的副本和其他操作,但不是全部。

此外,如果您是 C++ 新手,则不应使用 new。它是为专家准备的,只有在与同事讨论并喝了一杯浓咖啡后才能使用。 (当然,new 可能会被某些容器代为使用,例如std::vector。)

【讨论】:

  • 他可能没有直接使用new,而是std::vector在内部调用new
  • 您断言 new 只应由专家使用有点夸张。稍加思考,您就可以轻松地以安全且高效的方式使用 new。
  • 幸运的是,我自己没有使用新的。我还通过引用函数来传递向量,这是我已经发现的一件事:)
  • @ChaosPandion 实际上我非常不同意你的观点。新用户现在可以使用std::make_shared 在堆上实例化对象,而设计良好的 API 可以完全消除该要求。初学者无需使用它。
  • @Charles Salvia - 您不仅在猜测您看不到的代码,而且还在猜测背后隐藏的内容(分析器提到新的和免费的,但您猜想使用 std::vector 代替) .
【解决方案3】:

正如 Luchian Grigore 所说,std::vector 很昂贵。但不仅如此,代码中不断创建对象、移动数据、重新分配内存甚至删除它的任何部分都可能非常耗时。如果亚历克斯·张伯伦所说的是真的,那就有很大的瓶颈。如果不是,我会记得你(或者告诉你,如果你不知道的话),几乎你所做的每一件事都会使你的软件在内存消耗方面更便宜,它会以性能为代价。反之亦然,更多的内存消耗意味着 cpu 的计算量更少,因为您对之前计算的所有内容进行了缓存。这是基本的,但有时我们会忘记它。

【讨论】:

    【解决方案4】:

    避免在时间紧迫的代码上调用 new 和 delete。它很慢。或者使用快速内存​​管理器(例如 SmartHeap)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-16
      • 2012-03-20
      • 1970-01-01
      • 2012-04-18
      • 1970-01-01
      相关资源
      最近更新 更多