在 DEBUG 构建中,如果您将花费在每个函数上的所有时间加起来,您会得到大约 7 秒。这些数字加起来并不完全——你花了 142 秒来构建整个东西,但是这些函数只需要大约 7 秒来编译??
这是因为这些时间只是为了对每个函数体进行类型检查。在Swift frontend 中,您可以使用三个标志:
-Xfrontend -debug-time-compilation
-Xfrontend -debug-time-function-bodies
-Xfrontend -debug-time-expression-type-checking
让我们用第一个来看看全貌。选择一个慢速文件,例如Option.swift,然后查看:
===-------------------------------------------------------------------------===
Swift compilation
===-------------------------------------------------------------------------===
Total Execution Time: 30.5169 seconds (43.6413 wall clock)
---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
23.5183 ( 80.1%) 0.7773 ( 67.6%) 24.2957 ( 79.6%) 34.4762 ( 79.0%) LLVM output
3.7312 ( 12.7%) 0.0437 ( 3.8%) 3.7749 ( 12.4%) 5.4192 ( 12.4%) LLVM optimization
1.8563 ( 6.3%) 0.2830 ( 24.6%) 2.1393 ( 7.0%) 3.1800 ( 7.3%) IRGen
0.2026 ( 0.7%) 0.0376 ( 3.3%) 0.2402 ( 0.8%) 0.4666 ( 1.1%) Type checking / Semantic analysis
... <snip> ...
29.3665 (100.0%) 1.1504 (100.0%) 30.5169 (100.0%) 43.6413 (100.0%) Total
原来慢的不是 Swift,而是 LLVM!因此,没有必要查看类型检查时间。我们可以使用-Xllvm -time-passes 进一步检查为什么 LLVM 很慢,但它不会给我们提供有用的信息,它只是说X86 Assembly / Object Emitter 占用了大部分时间。
让我们退后一步,看看哪些文件编译时间最长:
Option.swift 30.5169
Toolbox.swift 15.6143
PictorialBarSerie.swift 12.2670
LineSerie.swift 8.9690
ScatterSerie.swift 8.5959
FunnelSerie.swift 8.3299
GaugeSerie.swift 8.2945
...
在Options.swift 中花费了半分钟。这个文件有什么问题?
- 你有一个巨大的结构,有 31 个成员。单独编译该结构需要 11 秒。
- 您有一个庞大的枚举,有 80 个变体。单独编译这个枚举需要 7 秒。
第一个问题很容易解决:改用final class!第二个问题没有简单的解决方法(我看不到任何时间改进的替代方法,例如用类替换枚举等级制度)。所有其他慢速文件都有类似的问题:大结构、大枚举。
只需将所有struct 替换为final class 就足以将编译时间从“超过几小时且仍在编译”缩短到“2.5 分钟”。
另见Why Choose Struct Over Class?。您的“结构”可能不符合structs 的条件。
请注意,从struct 更改为类确实会改变用户代码的语义,因为类具有引用语义。