【问题标题】:C++ performance: lists and iteratorsC++ 性能:列表和迭代器
【发布时间】:2011-12-13 09:01:08
【问题描述】:

我有一些继承的内部 C++ 代码,在 Windows 上使用 VC++ 编译时,运行速度比在 Linux 上使用 g++ 编译时快一个数量级(5 分钟对 2 小时)。无论有没有“正常”优化标志,以及每个编译器和各自平台的几个不同版本,都在可比较的硬件上,情况仍然如此。

在 Linux 上使用 g++ 构建调试/配置文件版本 (-g -pg),我发现以下三个方面大部分时间都在消耗:

%   cumulative   self              self     total
time   seconds   seconds    calls  Ks/call  Ks/call  name
31.95    955.93   955.93 3831474321     0.00     0.00  std::_List_const_iterator<xxFile>::operator!=(std::_List_const_iterator<xxFile> const&) const
22.51   1629.64   673.71 3144944335     0.00     0.00  std::_List_const_iterator<xxFile>::operator++()
15.56   2095.29   465.65 686529986      0.00     0.00  std::iterator_traits<std::_List_const_iterator<dtFile> >::difference_type std::__distance<std::_List_const_iterator<xxFile> >(std::_List_const_iterator<xxFile>, std::_List_const_iterator<xxFile>, std::input_iterator_tag)

(xxFile 类由整数、浮点数、双精度数、布尔值和字符串组成)

我的天真猜测是 VC++ 正在补偿一些编码不佳的东西,或者 GNU STL 可能没有得到优化。我目前正在使用 Boost 库编译 g++/Linux 版本,从 assign/std/list.hpp 和 boost::assign 命名空间开始。

我无法分享代码,但根据您的经验,是否有明显的原因(除了我有限的 C++ 经验之外)?

【问题讨论】:

  • 你是用g++ -O2编译的吗?您是否使用了最新的 GCC 编译器(4.6.2)?
  • 是的,确实如此,但我无法分享答案 ;-)
  • 我已经尝试过 -02 优化,我最近的尝试是在 Fedora 16(以及许多过去的版本)上使用 GCC 4.6.2。
  • 我可以冒险猜测,但猜测通常/通常是错误的。您正在使用gprof。不要使用gprof - 它不会告诉你真正的问题是什么。 Look here for reasons why, and an alternative.
  • 在 GCC(甚至 4.6.2)中有一些已知的错误,即 size() 不是 STL 集合的恒定时间。

标签: performance visual-c++ g++


【解决方案1】:

除了花费大量时间迭代列表之外,我会在不了解您的代码的情况下抛出几件事。

你需要使用列表吗?

如果您的大部分时间都花在迭代上,也许您应该使用连续的数据结构(数组/向量)。除非您出于某些其他原因需要列表行为(即,其他地方的大量插入,否则可能会主导您的运行时),由于内存局部性,使用数组应该会提供更好的性能。尽管迭代数组和列表都是 O(n),但实际上由于充分利用了 CPU 的缓存,数组可以更快。当你浏览一个列表时->下一个你不知道你可能会在哪里结束,如果你总是出现页面错误,你的表现会很糟糕。

您是否进行了大量搜索?可能有很多线性搜索?

运算符 != 位于列表顶部的事实使其以这种方式显示。谁在打电话,为什么?如果您正在执行大量搜索并且这会支配您的运行时,您可能还需要考虑不同的数据结构,如果您执行大量插入和查找,则可能是二叉搜索树或哈希表。

【讨论】:

  • 重写以将数据结构更改为有助于提高性能的连续性的好点。
【解决方案2】:

因为最重要的项目是距离、运算符++ 和运算符!= 我相信您的问题是在列表上使用size() 操作。

这是 C++ 标准允许不同实现的领域之一。 MSVC 实现将列表的大小存储为数字,因此返回值非常快。 GCC 没有,因此要获得列表的大小,它必须基本上执行:

count = 0;
for(
    list::iterator it = l.begin()
    it != l.end();
    ++it
)
    ++count;

在该循环中,您可以看到您的个人资料中的每个操作。

【讨论】:

  • 谢谢!这个网址好像支持~linuxprogrammingblog.com/std-list-size-complexity~不想重写代码,我去看看单独的STL。
  • Everyone... 我使用 boost::interprocess' 列表重建了 Linux 应用程序,该列表在其标头中指出了 O(1) size() 复杂性(可能是由于计数变量与迭代)和它现在可以与 Windows 版本相提并论了!约 5 分钟,而不是几小时!我相信一旦 GNU c++ 完全整合了 C++11,它们就会匹配这个性能,因为这个函数的恒定性能似乎在规范中定义。
猜你喜欢
  • 2019-08-22
  • 2012-10-11
  • 1970-01-01
  • 2013-02-07
  • 2013-04-09
  • 1970-01-01
  • 2015-10-24
  • 2013-11-25
  • 1970-01-01
相关资源
最近更新 更多