Swift 类型检查在非常短的函数上花费的时间太长
Swift Type Checking Takes Too Long on Very Short Function
我已将 Swift 编译器标志 -warn-long-function-bodies
设置为 90 毫秒,以查看我项目中的哪些函数编译时间过长(由于类型检查)。
我有以下方法:
func someKey(_ sectionType: SectionType, row: Int) -> String {
let suffix = row == 0 ? "top" : "content"
return "\(sectionType)_\(suffix)"
}
(SectionType
是一个支持字符串的枚举)
如上所示,在 2017 款 MacBook Pro 上需要 96 毫秒。我尝试的第一件事是绕过字符串插值并使用 \(sectionType.rawValue)
而不是 \(sectionType)
,但现在它给了我 106 ms。走错了...
接下来我改成:
let suffix = row == 0 ? "top" : "content"
至:
let suffix = "top"
警告消失,所以是三元运算符引起了麻烦。
我试过这个:
let suffix: String = { // Note the type annotation!
if row == 0 {
return "top"
}
return "content"
}()
...但现在是 闭包 需要 97 毫秒(整个函数,101)。
我什至尝试了更明确的:
let suffix: String = {
if row == 0 {
return String("top")
} else {
return String("content")
}
}()
...我得到关闭:94ms;函数:98ms.
怎么回事?
我的 90 毫秒限制是否太低?我知道有(是?)dictionary 文字的类型检查错误,但这似乎完全不同......?
我的环境是Xcode8.3.2(8E2002),
Swift: Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42)
但是等等!还有更多...
我试过这个函数体:
func someKey(_ sectionType: SectionType, row: Int) -> String {
if row == 0 {
return "\(sectionType.rawValue)_top"
} else {
return "\(sectionType.rawValue)_content"
}
}
...而且需要97ms~112ms!?
附录: 我将函数和枚举移植到一个干净、最小的项目(单视图应用程序)中,设置了相同的警告,但它没有发生。我确信整个项目正在以某种方式影响这种方法,但还不太清楚如何...
附录 2:我测试了函数的静态版本:使用固定后缀 "top" 而不管 row
的值(这需要少于90 毫秒并且触发无警告),但是 添加了以下 if
块:
func someKey(_ sectionType: SectionType, row: Int) -> String {
if row == 0 {
print("zero")
} else {
print("non-zero")
}
let suffix: String = "top"
return "\(sectionType)_\(suffix)"
}
这让我回到了 96~98 毫秒! 所以当比较行与零时问题出现了?
解决方法: 我一直在研究我的代码,不知何故发现,如果我用 switch
语句替换 if
块,问题就会消失:
func someKey(_ sectionType: SectionType, row: Int) -> String {
let suffix: String = {
switch row {
case 0:
return "top"
default:
return "content"
}
}()
return "\(sectionType)_\(suffix)"
}
(我不会回答我自己的问题,因为我不认为这是对实际情况的解释)
我认为是三元运算符。
我在 Xcode 11(~93 毫秒)中得到了类似的结果,但编译时间减少到~23 毫秒:
func someKey(_ sectionType: SectionType, row: Int) -> String {
var suffix = "top"
if row != 0 {
suffix = "content"
}
return "\(sectionType)_\(suffix)"
}
通过改变这一行的逻辑,我想我们可以证明它是三元逻辑,因为该方法减少到~1ms。我刚刚将行设为布尔值。
func someKey(_ sectionType: SectionType, row: Bool) -> String {
let suffix = row ? "top" : "content"
return "\(sectionType)_\(suffix)"
}
同样(没有双关语意)将三元逻辑更改为 let suffix = row != 0 ? "top" : "content"
将编译时间减半。这与我的第一个代码块相当。 !=
Swift 比 ==
理解起来更快。
我已将 Swift 编译器标志 -warn-long-function-bodies
设置为 90 毫秒,以查看我项目中的哪些函数编译时间过长(由于类型检查)。
我有以下方法:
func someKey(_ sectionType: SectionType, row: Int) -> String {
let suffix = row == 0 ? "top" : "content"
return "\(sectionType)_\(suffix)"
}
(SectionType
是一个支持字符串的枚举)
如上所示,在 2017 款 MacBook Pro 上需要 96 毫秒。我尝试的第一件事是绕过字符串插值并使用 \(sectionType.rawValue)
而不是 \(sectionType)
,但现在它给了我 106 ms。走错了...
接下来我改成:
let suffix = row == 0 ? "top" : "content"
至:
let suffix = "top"
警告消失,所以是三元运算符引起了麻烦。
我试过这个:
let suffix: String = { // Note the type annotation!
if row == 0 {
return "top"
}
return "content"
}()
...但现在是 闭包 需要 97 毫秒(整个函数,101)。
我什至尝试了更明确的:
let suffix: String = {
if row == 0 {
return String("top")
} else {
return String("content")
}
}()
...我得到关闭:94ms;函数:98ms.
怎么回事?
我的 90 毫秒限制是否太低?我知道有(是?)dictionary 文字的类型检查错误,但这似乎完全不同......?
我的环境是Xcode8.3.2(8E2002),
Swift: Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42)
但是等等!还有更多...
我试过这个函数体:
func someKey(_ sectionType: SectionType, row: Int) -> String {
if row == 0 {
return "\(sectionType.rawValue)_top"
} else {
return "\(sectionType.rawValue)_content"
}
}
...而且需要97ms~112ms!?
附录: 我将函数和枚举移植到一个干净、最小的项目(单视图应用程序)中,设置了相同的警告,但它没有发生。我确信整个项目正在以某种方式影响这种方法,但还不太清楚如何...
附录 2:我测试了函数的静态版本:使用固定后缀 "top" 而不管 row
的值(这需要少于90 毫秒并且触发无警告),但是 添加了以下 if
块:
func someKey(_ sectionType: SectionType, row: Int) -> String {
if row == 0 {
print("zero")
} else {
print("non-zero")
}
let suffix: String = "top"
return "\(sectionType)_\(suffix)"
}
这让我回到了 96~98 毫秒! 所以当比较行与零时问题出现了?
解决方法: 我一直在研究我的代码,不知何故发现,如果我用 switch
语句替换 if
块,问题就会消失:
func someKey(_ sectionType: SectionType, row: Int) -> String {
let suffix: String = {
switch row {
case 0:
return "top"
default:
return "content"
}
}()
return "\(sectionType)_\(suffix)"
}
(我不会回答我自己的问题,因为我不认为这是对实际情况的解释)
我认为是三元运算符。
我在 Xcode 11(~93 毫秒)中得到了类似的结果,但编译时间减少到~23 毫秒:
func someKey(_ sectionType: SectionType, row: Int) -> String {
var suffix = "top"
if row != 0 {
suffix = "content"
}
return "\(sectionType)_\(suffix)"
}
通过改变这一行的逻辑,我想我们可以证明它是三元逻辑,因为该方法减少到~1ms。我刚刚将行设为布尔值。
func someKey(_ sectionType: SectionType, row: Bool) -> String {
let suffix = row ? "top" : "content"
return "\(sectionType)_\(suffix)"
}
同样(没有双关语意)将三元逻辑更改为 let suffix = row != 0 ? "top" : "content"
将编译时间减半。这与我的第一个代码块相当。 !=
Swift 比 ==
理解起来更快。