C++ 中的循环展开2025年5月13日 | 阅读 9 分钟 C++ 循环展开简介程序员用于提高性能的最后一种技术被称为循环展开。循环展开是一种提高循环处理速度并同时消除某些迭代指令的技术。简而言之,循环展开以每次迭代执行的指令数来交换循环迭代的次数。这可以显著提高索引性能,尤其是在应用程序需要大量计算周期的情况下,例如科学计算、图形处理和高性能数据处理。但是,要了解循环展开为什么有效,我们需要了解普通循环的形式以及其底层的开销。 什么是循环开销,为什么它很重要?在传统的循环中,例如 C++ 中的 for 循环,有几个关键组成部分:
在小型循环中,检查循环条件和更新循环变量所需的时间并不显著。然而,当循环在大型应用程序中执行数百万甚至数十亿次时,这些前置控制操作的成本很高。每次执行一次,在条件检查、分支和增量方面都会产生少量的计算成本。第三,当今的大多数处理器都经过优化,可以同时运行指令,这被称为指令级并行。然而,传统循环的结构有时不允许处理器充分利用此功能,例如,如果循环体的长度只有几条指令。 手动与编译器自动循环展开我的意思是,循环展开可以手动执行,就像上面提到的那样,也可以由编译器执行。包括 GCC、Clang 和 MSVC 在内的现代编译器都能够根据某些条件对循环进行完全自动展开的优化。例如,使用 GCC 编译器,如果将优化级别设置为 -O3,它会指示编译器优化代码大小,并且它会检查的要求之一是,如果编译器认为合适,它将展开循环。 然而,编译器执行的展开仍然存在其缺点。一些编译器在使用展开时可能会很保守,因为添加比所需更多的代码可能会弊大于利。手动循环展开尤其有利,因为它允许程序员为代码的特定部分微调展开,在这些部分希望以特定的方式和特定的间隔进行展开。 循环展开的好处循环展开的主要优势是消除了循环开销,这直接带来了期望的改进,尤其是在迭代次数很高的循环中。其次,展开增强了指令级并行性,因为处理器将能够通过一次执行这些指令来利用其资源。它还可以改善缓存使用,因为每次迭代处理更多数据在某些情况下可能导致更少的缓存未命中。 缺点和权衡然而,需要注意的是,循环展开并非完全没有优点。第一个也是可能最显著的缺点是使用动态 对象 伴随的代码大小膨胀。每个展开的循环都会复制循环体,这会导致新的大型程序或大型程序的开发。这就是为什么当使用大型二进制文件时,它们倾向于影响内存消耗,在某些情况下甚至可能导致较差的缓存性能。此外,当手动展开循环时,代码可能会显得僵化且难以维护,可读性也较差,特别是当循环复杂时。这会使调试、修改甚至扩展其在未来发展中的功能代码形式变得更具挑战性。 循环展开如何工作:分步解析循环展开是一种通过优化方法尝试从代码中去除重复控制形式的过程。for 或 while 任何基本类型的循环都存在测试和控制操作;测试条件、循环变量的增加或跳转回循环体指令都需要时间。虽然这里提到的步骤可能需要几个处理器周期,但如果应用于运行数千或数百万次的循环,其差异将是巨大的。循环展开试图避免频繁执行这类控制操作,因为目标是减少迭代次数,同时最大化每次循环迭代所做的工作。
循环展开的类型循环展开主要可以分为两类:完全展开和部分展开处理。这些变体提供了解决循环展开的冲突目标的能力,一方面,它带来了更高效的代码,另一方面,这些好处可能会被最大的代码大小和某些级别的代码复杂性所掩盖。 完全展开
部分展开
编码 输出 Traditional loop sum: 100000000 Traditional loop duration: X.XXXX seconds Partially unrolled loop sum: 100000000 Partially unrolled loop duration: Y.YYYY seconds Further unrolled loop sum: 100000000 Further unrolled loop duration: Z.ZZZZ seconds 结论总之,循环展开 是一种有效的 C++ 优化技术,它减少了循环控制开销,从而加快了大型循环的执行速度。与通过增加每次迭代的工作量来最小化条件检查和 变量 更新等重复操作的展开不同,好的推测性存储合并软件缓存流编译器将使用这些缓存来增加每次迭代的工作量,从而减少推测性未命中。该技术旨在提供指令级并行性,因此适用于高性能应用程序。虽然引入部分或全部循环可以带来惊人的加速,但它会以代码大小和复杂性增加为代价。循环展开非常适合性能敏感的领域,在这些领域您需要速度胜过简洁性。通过适当的平衡,您可以获得足够的优化,而不会过度膨胀代码。 |
在数论和组合学的领域中,弗罗贝尼乌斯数是源自一个经典数学问题(在娱乐数学中称为硬币问题或鸡块问题)的著名概念。这个问题围绕着确定最大整数的想法……
阅读 8 分钟
在本文中,我们将讨论 C++ 中的 multimap size() 函数。但在了解 size() 函数之前,我们必须了解 multimap。Multimap 是 C++ 中的一个排序容器,存在于标准模板库中。通常,map 存储键值对...
阅读 3 分钟
在本文中,我们将通过不同的方法讨论它。在讨论其方法之前,我们必须先了解 C++ 中的 Nicomachus 定理。用一个例子解释 Nicomachus 定理 k 的平方等于从 1 到 k 的奇数的和……
阅读 17 分钟
C++17 具有多项有价值的特性,可增强语言的表达力和灵活性。“std::variant”是一种强大的处理变体类型的工具。std::variant 存在于 阅读 4 分钟
STL 是标准模板库的缩写,我们在其中拥有许多可用的功能代码。在 C++ 中,max_element 或 std::max_element() 是标准模板库中可用的算法,它主要用于检索其中可用的最大元素……
7 分钟阅读
在本文中,您将学习 C++ 中的后缀 Trie,包括其历史、实现、应用、优点和缺点。C++ 中的 Trie 是什么?Trie 也称为前缀树。它是一种树状数据结构,用于...
阅读 10 分钟
在本文中,我们将讨论 C++ 中的 Std::codecvt_out 和 Std::do_out 函数及其特性、示例、优点和缺点。引言:自创建以来,文本处理和字符编码一直是 C++ 的核心。随着该语言的发展,其方法也为...
阅读 6 分钟
C 和 C++ 是两种经久不衰的计算机语言。这两种语言在软件开发方面都具有强大的特性,程序员必须能够区分它们之间细微的差别。其中一种发生变化的地方是在...
5 分钟阅读
自传数(n)是指定基数中的一个 b 位整数。在该数中,位置 p(其中最高有效位是位置 0,最低有效位是位置 (b−1))处的每个数字反映了该数字出现的次数...
5 分钟阅读
理解霍夫施塔特数列(Hofstadter sequence)是一个有趣的数学序列,常用于在编程中演示递归和算法问题解决方法。它以美国计算机科学家道格拉斯·霍夫施塔特(Douglas Hofstadter)的名字命名。这个序列一直是计算理论中许多探索的主题,而且……
5 分钟阅读
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India