关于C#:STL替代

关于C#:STL替代

STL Alternative

我真的很讨厌使用STL容器,因为它们使我的代码的调试版本运行得非常慢。其他人会使用什么替代具有合理性能的STL来进行调试构建?

我是一名游戏程序员,这对我从事的许多项目都是一个问题。将STL容器用于所有内容时,很难获得60 fps。

我的大部分工作都使用MSVC。


EASTL是可能的,但仍不完美。 Electronic Arts的Paul Pedriana对游戏应用程序中的性能进行了各种STL实现的调查,其摘要如下:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html

其中的一些调整正在接受审查,以纳入C标准。

请注意,即使是EASTL也无法针对未优化的情况进行优化。我有一个带有一段时间的excel文件,但我想我已经丢失了,但是访问它就像:

1
2
3
4
       debug   release
STL      100        10
EASTL     10         3
array[i]   3         1

我获得的最大成功是滚动自己的容器。您可以将这些性能降低到接近array [x]的性能。


我的经验是,由于关闭了优化程序,因此设计良好的STL代码在调试版本中运行缓慢。 STL容器会向构造函数和operator =发出大量调用,这些调用会在发布版本中内联/删除(如果它们很轻便)。

此外,Visual C 2005及更高版本在发布和调试版本中都启用了STL检查。对于STL繁重的软件而言,这是一个巨大的性能消耗。可以通过为所有编译单元定义_SECURE_SCL = 0来禁用它。请注意,在不同的编译单元中具有不同的_SECURE_SCL状态几乎肯定会导致灾难。

您可以在关闭检查的情况下创建第三个构建配置,并使用它来进行性能调试。我建议您保留调试配置,但是要进行检查,因为捕获错误的数组索引和类似的东西非常有帮助。


如果您正在运营视觉工作室,则可能需要考虑以下事项:

1
2
#define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0

仅用于迭代器,您要执行哪种类型的STL操作?您可能需要考虑优化内存操作。即,使用resize()一次插入多个元素,而不是一次使用pop / push一次插入一个元素。


对于大型,性能至关重要的应用程序,构建自己的容器以专门满足您的需求可能值得您花时间投资。

我在这里谈论真正的游戏开发。


如果使用的是Visual C,则应查看以下内容:

http://channel9.msdn.com/shows/Going Deep / STL-Iterator-Debugging-and-Secure-SCL /

以及该页面上的链接,其中涵盖了MS / Dinkware STL进行的所有调试模式检查的各种成本和选项。

如果您要问这样一个依赖于平台的问题,也最好提一下您的平台...


我敢打赌,您的STL使用已检查的实现进行调试。这可能是一件好事,因为它将捕获迭代器超载等。如果这对您来说是个大问题,则可能有编译器开关将其关闭。检查您的文档。


对不起,我不能发表评论,所以这是一个答案:EASTL现在可以在github上找到:https://github.com/paulhodge/EASTL


MSVC在调试版本中使用了检查迭代器的非常重的实现,其他人已经讨论过,所以我不再重复(而是从此处开始)。

您可能会感兴趣的另一件事是,您的"调试版本"和"发行版本"可能涉及更改(至少)四个松散相关的设置。

  • 生成一个.pdb文件(cl / Zi和链接/ DEBUG),该文件允许进行符号调试。您可能需要将/ OPT:ref添加到链接器选项;链接器在不制作.pdb文件时会丢弃未引用的函数,但是在/ DEBUG模式下,除非您明确添加,否则链接器会保留所有未引用的函数(因为调试符号引用了它们)。
  • 使用C运行时库的调试版本(可能是MSVCR * D.dll,但这取决于您使用的运行时)。可以归结为/ MT或/ MTd(如果不使用dll运行时,则可以归为其他)
  • 关闭编译器优化(/ Od)
  • 设置预处理器#define DEBUG或NDEBUG
  • 这些可以独立切换。尽管增加了大小,但第一个在运行时性能上不付出任何代价。第二个功能使许多功能更昂贵,但对malloc和free具有巨大影响;调试运行时版本会小心地使用值"毒化"它们接触的内存,以清除未初始化的数据错误。我相信通过MSVCP * STL实现,它还消除了通常需要完成的所有分配池,因此泄漏恰好显示了您认为的块,而不是它正在分配的更大的内存块。这意味着在它们之上进行更多的malloc调用要慢得多。第三;好吧,那可以做很多事情(这个问题对该主题有一些很好的讨论)。不幸的是,如果您希望单步操作顺利进行,则需要它。第四种以各种方式影响许多库,但是最值得注意的是它可以编译或消除assert()和朋友。

    因此,您可以考虑使用这些选项的较小组合来进行构建。我大量使用具有符号(/ Zi和链接/ DEBUG)和断言(/ DDEBUG)的构建,但仍进行了优化(/ O1或/ O2或您使用的任何标志),但保留了堆栈帧指针清除回溯(/ Oy-)并使用常规运行时库(/ MT)。这与我的发布版本很接近,并且是半可调试的(回溯很好,在源代码级别,单步执行有些怪异;汇编级别当然可以工作)。但是,您可以具有许多所需的配置。只需克隆您的发行版一个,然后打开调试中似乎有用的任何部分。


    查看EASTL。


    Qt使用不同的接口重新实现了大多数c标准库内容。它看起来不错,但是对于商业许可版本来说可能会很昂贵。

    编辑:此后,Qt已在LGPL下发布,通常可以在不使用商业版本(也仍然存在)的情况下将其用于商业产品。


    C语言中具有面向对象设计模式的检出数据结构和算法
    布鲁诺·普雷斯(Bruno Preiss)
    http://www.brpreiss.com/


    ACE库怎么样?这是一个用于并发通信软件的面向对象的开源框架,但是它也具有一些容器类。


    终极版有自己的一组容器-不确定是否可以将它们与库的其余部分分开使用:http://www.ultimatepp.org/


    还有ETL https://www.etlcpp.com/。该库特别针对时间关键型(确定性)应用程序

    来自网页:

    The ETL is not designed to completely replace the STL, but complement
    it. Its design objective covers four main areas.

    • Create a set of containers where the size or maximum size is determined at compile time. These containers should be largely
      equivalent to those supplied in the STL, with a compatible API.
    • Be compatible with C++ 03 but implement as many of the C++ 11 additions as possible.
    • Have deterministic behaviour.
    • Add other useful components that are not present in the standard library.

    The embedded template library has been designed for lower resource
    embedded applications. It defines a set of containers, algorithms and
    utilities, some of which emulate parts of the STL. There is no dynamic
    memory allocation. The library makes no use of the heap. All of the
    containers (apart from intrusive types) have a fixed capacity allowing
    all memory allocation to be determined at compile time. The library is
    intended for any compiler that supports C++03.


    STL容器在调试或其他任何地方都不应"真正缓慢地"运行。也许您是在滥用它们。您在调试中没有遇到类似于ElectricFence或Valgrind的问题吗?他们会减慢进行大量分配的速度。

    所有容器都可以使用自定义分配器,有些人可以使用它们来提高性能-但我从来不需要自己使用它们。


    推荐阅读