假设有以下三个简单函数:
func twice_Array_of_Int(a: [Int]) -> [Int] {
return a + a
}
func twice_Array_of_T<T>(a: [T]) -> [T] {
return a + a
}
func twice_Array_of_Any(a: [AnyObject]) -> [AnyObject] {
return a + a
}
假设使用发布版(
-Os
),您认为它们的性能会如何比较?我期望
[Int] -> [Int]
比 [AnyObject] -> [AnyObject]
快得多...而且确实是...快了好几个数量级。然而,我也期望
[T] -> [T]
的表现要比 [AnyObject] -> [AnyObject]
好得多,几乎与 [Int] -> [Int]
一样快...对吗?结果证明我错了:即使是
[AnyObject] -> [AnyObject]
(包括转换回到[Int]
),也比[T] -> [T]
快5倍!这是令人失望的,尤其是因为泛型是 Swift 最有前途的特性之一。在 Apple 的 WWDC 视频中,工程师们提到他们正在本地实现泛型,即使用它们不会导致代码膨胀。这是否解释了
[T] -> [T]
的性能差?如果他们只是在编译时扩展通用函数,那么 [T] -> [T]
和[Int] -> [Int]
的性能应该是相同的,对吗?以下是测试代码:
func testPerformance_twice_Array_of_Int() {
let a = Array(1...100_000)
self.measureBlock {
let twice_a = twice_Array_of_Int(a)
}
// average: 0.000, relative standard deviation: 76.227%
}
func testPerformance_twice_Array_of_T() {
let a = Array(1...100_000)
self.measureBlock {
let twice_a = twice_Array_of_T(a)
}
// measured [Time, seconds] average: 0.554, relative standard deviation: 7.846%
}
func testPerformance_twice_Array_of_Any() {
let a = Array(1...100_000)
self.measureBlock {
let twice_a = twice_Array_of_Any(a) as [Int]
}
// average: 0.115, relative standard deviation: 8.303%
// without the cast to [Int] = average: 0.039, relative standard deviation: 2.931%
}
我很想听听你的意见,以及你如何计划将其纳入你的代码设计中。
编辑
我刚刚进行了一项更简单的测量,结果更加惊人:
func ==(lhs: (Int, Int), rhs: (Int, Int)) -> Bool {
return lhs.0 == rhs.0 && lhs.1 == rhs.1
}
相比之下:
func ==<T: Equatable>(lhs: (T, T), rhs: (T, T)) -> Bool {
return lhs.0 == rhs.0 && lhs.1 == rhs.1
}
结果:
func testPerformance_Equals_Tuple_Int() {
let a = (2, 3)
let b = (3, 2)
XCTAssertFalse(a == b)
let i = 1_000_000
self.measureBlock() {
for _ in 1...i {
let c = a == b
}
// average: 0.002, relative standard deviation: 9.781%
}
}
相比之下:
func testPerformance_Equals_Tuple_T() {
let a = (2, 3)
let b = (3, 2)
XCTAssertFalse(a == b)
let i = 1_000_000
self.measureBlock() {
for _ in 1...i {
let c = a == b
}
// average: 2.080, relative standard deviation: 5.118%
}
}
通用版本的中缀函数要慢1000多倍!
编辑2:
8月21日,奥斯丁·郑在一次Swift语言用户组聚会上发表了题为“Enums、模式匹配和Generics”的演讲(特别嘉宾克里斯·拉特纳)。他说,Swift会为常见类型生成优化代码,但必要时会回退到本地通用版本的函数以满足运行时需要。参考:http://realm.io/news/swift-enums-pattern-matching-generics/ (从32:00开始) 。
编辑3:
Swift 2已经发布,这个问题已经迫切需要更新(只要我有喘息时间就会更新)...
最快、最小[-Os]
。 - Milos