在C语言中将单个文件拆分成多个文件 - 性能方面

5
我在这个主题上找到了一个类似的帖子,但它涉及设计方面而不是性能,所以我发帖想了解将大型c文件拆分成基于模块的函数文件(cookies.c、memcacheutils.c、stringutils.c、search.c、sort.c、arrayutils.c等)是否会影响编译和执行时间。
我的常识告诉我,这样做会增加一些开销,因为代码现在必须在远处的地方查找指针,而不是在同一个文件中。我可能非常错误或部分正确。寻求所有专家的指导。我当前的utils文件约为150k,有80多个函数。
谢谢阅读此帖。

你必须估计项目的性能时间惩罚与开发时间惩罚。将一个大文件分成多个小文件通常会增加一级或多级指针间接性,但可以简化开发人员或维护人员的工作。 - lucasg
为了可维护性,请将这个怪物切成片! - alk
Microsoft Windows 项目是一个需要为每个文件导入 windows.h 的领域,如果没有头文件缓存,这可能会花费很长时间。将代码拆分成多个文件是否会影响编译性能是一个合理的问题。 - PP.
6个回答

4
通常将项目分成多个编译单元可以更好地管理项目并实现更快的部分编译。当您编辑一个文件时,只需要重新编译该编译单元并重新链接以进行测试和调试。
但是,根据您的编译器,将所有内容放在一个文件中可能会允许额外的内联和功能优化,但代价是编译时间较长。

我见过一些项目在分成多个文件后会变慢...难道说这样做可以加快编译速度吗?我认为只是不同的方式而已。 - Hogan
1
这就是为什么我说更快的部分编译。 - Sergey L.
啊,你在技术上抓住我了。没错。我认为你的回答可能会被误解。 - Hogan

3

您应该始终将源代码分段为逻辑单元。

这样做还有更快的编译速度,因为每次更改时不需要重新编译所有内容。同时维护这样的源代码也很可怕,跟踪与生产相关的更改也很困难。

如果一个函数位于不同的模块中,那么不会有性能收益/惩罚,最多只会增加一个额外的jmp指令。如果您的代码确实依赖机器周期,则应首先考虑算法设计。


1
更快的编译取决于构建系统和编译器。有许多编译器无法提供这种速度提升。 - Hogan

3

在有不同段的16位PC上,这曾经很重要。远(更糟的是,“巨大”)指针会带来性能成本,因为您必须开始玩弄段寄存器。

如今,由于32位寻址,就不应该再有成本了。如果您真的很担心性能问题,那么就考虑在汇编语言中使用“跳转表”,需要将目标地址放在相对于当前指令的短距离处。

因此,在C中,您确实应该将代码放在不同的模块中(了解软件“内聚性”和“耦合性”的理论问题)。执行时间不应该有任何区别。关于编译时间,这是“取决于” - 特别是如果您重复包含文件。在一个大型项目中,使用多个文件可以节省大量时间,因为您只需重新编译已更改的代码单元。在小项目中,编译时间太小,相对无关紧要,不需要担心效率。


你可以始终使用16位编译器的微型内存模型,这不会有任何影响。 - Hogan
@Hogan同意。然而,当时使用更大的内存模型确实会对性能产生影响。 - PP.
2
分离编译单元和内存模型是两个完全独立的问题。 - Jan Hudec

2
编译时间会改变。
(注意 - 任何能够进行增量编译的系统和项目都会更快。)
如果代码除了分裂成文件之外没有任何更改,则最终结果不会改变。
如果在代码中包含调试信息,则最终代码结果将随着更多文件而改变,但我不希望出现性能差异。
顺便说一下,我认为没有一个曾经使用过大型系统的程序员会告诉你不要拆分文件。你必须这样做才能使大型系统易于维护。我不知道你的系统是否已经达到了那个点,但早期做这件事是没有害处的。拆分文件。

编译时间将会改变。它会更快还是更慢?我认为会更快,因为许多目标文件不必在.cpp文件内部没有变化时重新编译。 - hetepeperfan
@hetepeperfan - 这取决于编译器、链接器和构建过程。我曾经使用过一些系统,它们会变得更快,也有一些系统会变得更慢。 - Hogan

1
这不会增加任何性能惩罚。即使有,这也是一种过早优化。唯一重要的是开发时间。
如果您发现已经确保所有算法具有最优复杂度,调整了所有内部循环以获得最大性能,并且仍需要削减运行时的一些纳秒,您可以创建一个源文件,将所有拆分的源文件都 #include 到一个大块中交给编译器。

0
关于运行时性能,我建议进行一些性能测量,具体取决于您在性能损失方面的敏感程度。到目前为止,答案的共识是将文件拆分成较小的单元不会降低运行时性能,但这取决于您对“性能”的定义。
如果您真的非常关注最轻微的性能损失,除非启用了整个程序优化并且它有效,否则编译器可能会错过一些优化机会,如果您的文件被拆分(当然这取决于代码风格、全局变量的使用、内联的使用(请记住,在某些情况下,不内联可能会产生更好的结果)、静态类/方法是否使用c++等)。
我怀疑在某些边缘情况下,一个单一的源文件可能会带来微小的性能提升(而在其他情况下,它可能会降低性能!)。在几个简单的场景中进行测试,包括改变编译器的优化级别,将是一个相当有趣的实验。
我认为你不会找到任何硬性规定,比如“将一组相关的大型函数拆分成两个源文件总是可以的”,但你可能会发现对于特定的编译器设置和源文件,拆分文件甚至可能会导致微妙的问题,例如影响指令缓存的性能(取决于你的性能测试有多细致)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接