我有5个函数被调用10000次(平均)。所有这些都修改/使用了某些变量。
我知道拥有全局变量是不好的做法。但是出于性能的考虑,将它们保持全局而不是传递它们是否有意义 - 特别是当我多次进行函数调用时?
或者我在性能方面不会获得太多收益?
答案 0 :(得分:8)
出于性能目的,不要引入全局变量/全局状态。这是错误的,与所有良好的编码实践相反,通常无助于性能(甚至可能会受到伤害)。
如果您发现传递大量变量的代价太高,可以将它们全部放在上下文struct
中并将单个指针传递给struct
。这样就可以避免创建全局状态(偶数static
存储持续时间变量是全局状态),这会阻止您的代码在多个实例中使用。成本几乎为零,实际上它在位置无关代码(共享库或位置无关的可执行文件)中的成本低于全局变量。
答案 1 :(得分:4)
性能的变化绝对取决于许多事情,其中最重要的是你正在开发的平台。 如果您正在开发一个微型微处理器,将参数复制到堆栈(从调用函数)和访问堆栈所花费的时间可能占总执行时间的足够比例保证。
请注意,在传递参数所花费的时间很长的情况下,可能发现其他一些建议(例如,将指针传递给结构,将指针传递给静态变量)将无法提供任何好处。使用全局变量确实为编译器/链接器提供了对这些变量进行硬编码访问的机会,而不必间接地从堆栈上的指针访问它们。这与没有任何缓存的处理器特别相关。
当然这都是非常目标依赖,并且高度依赖于您正在使用的处理器的指令集。在任何具有合理指令集的平台上,您都应该看到改进。
但是,只有在对此代码进行概要分析后才能采取此类措施。在大多数平台上,使用任何非平凡函数,传递参数并访问它们所花费的时间是微不足道的。任何潜在的性能提升都将以更难以维护的代码为代价。
通过使用其他优化技术,您很可能会获得更高的性能提升。检查this问题以了解一些尝试方法。
编辑:我从你的一条评论中看到你还处于这个项目的设计阶段。
在这个过程中做出这样的优化还为时过早。在这个阶段,通过优化您使用的算法,您将对性能产生更大的影响,而不是像这样在指令级别进行最小化。
答案 2 :(得分:3)
静态变量是C具有文件范围,在您的情况下它们可能就足够了 - 前提是您可以将函数分组到1个文件中。对我来说,静态变量比全局变量要少几个数量级。
一个经常被忽视的问题是在函数体内声明的变量将在堆栈上分配,而静态变量通常从名为bss的较少限制的内存池中分配。因此,将所有变量整齐地定义在函数内部可能会导致堆栈耗尽问题,并且可以通过静态以非常干净的方式避免这种情况。
答案 3 :(得分:2)
我会说全局变量可能比传递参数慢。参数存在于大量使用的堆栈上,因此很可能位于缓存中。全局变量存在于静态空间中,使用的空间要少得多,因此不太可能在缓存中使内存查找速度慢得多。由于缓存考虑,您的跳转(到新函数)可能是整个函数调用操作中最慢的部分。
如果您的功能很小,请查看内联。如果它们很大,很可能在堆栈上推一两个字会产生最小的差异。
另请注意,使用堆栈进行参数传递非常重要。 ARM和其他具有大量寄存器的体系结构通常会使用一些寄存器来传递非常快的参数。
答案 4 :(得分:2)
在某些嵌入式微控制器上,使用全局变量而不是参数可能会带来性能优势,但这是依赖于机器的。
例如,使用典型的8位微控制器编译器(HT-PICC18)时,设置全局变量的成本是每个字节两个指令/两个周期。传递一个单字节参数成本指令/一个周期。传递两个或更多字节的参数每个字节花费两个周期。因此,传递两个单字节参数的最有效方法是将一个作为参数传递,将一个作为全局传递。
在68HC11的Introl编译器中,具有任何自动变量或参数的例程需要多指令序言和结尾,如果所有变量都是静态的并且参数作为全局变量传递,则可以省略。但是,如果例程将使用任何本地或参数,则使用本地和参数的边际成本可以忽略不计。
在ARM上,即使没有缓存,反向情况也经常适用:访问自动变量或参数通常比访问全局变量更快。自动变量和参数将位于寄存器中,或者与存储在寄存器中的地址处于可直接访问的已知偏移量。相反,访问全局变量通常是一个两步过程:首先加载全局变量的地址,然后自己访问变量。
答案 5 :(得分:1)
人们通常会试图远离全球参数,除非他们确实需要它们(即除非真正具有全球状态)。特别是对于多线程应用程序,使用全局参数可以使事情变得比他们需要的更困难。
就性能而言,我听到一些人暗示在某些情况下访问全局变量可能更快,虽然我觉得很难相信,但唯一可以确定的方法是实际上为你的特定情况做一些基准测试。
就个人而言,我永远不会这样做。我会考虑参数传递给函数的方式(确保它是通过指针,而不是通过复制,例如,在大数据类型的情况下),并确保传递正确的(最佳)优化设置编译器。
希望这有帮助。
答案 6 :(得分:0)
我认为你不会通过用全局变量替换参数来提高性能。
无论如何,如果你想这样做,你也可以考虑在同一个文件中声明所有函数和变量,并将变量声明为static。这样,只有在同一文件中声明的函数才能访问它们。