我正在用Swift编写一些性能关键代码.在实现了我能想到的所有优化,并在仪器中分析了应用程序之后,我开始意识到,绝大多数CPU周期都花在对浮点数组执行map()
和reduce()
操作上.所以,为了看看会发生什么,我用老式的for
循环替换了map
和reduce
的所有实例.令我惊讶的是...for
圈的速度要快得多!
对此有点困惑,我决定执行一些粗略的基准测试.在一次测试中,我让map
人在执行以下简单算法后返回一个浮点数组:
// Populate array with 1,000,000,000 random numbers
var array = [Float](count: 1_000_000_000, repeatedValue: 0)
for i in 0..<array.count {
array[i] = Float(random())
}
let start = NSDate()
// Construct a new array, with each element from the original multiplied by 5
let output = array.map({ (element) -> Float in
return element * 5
})
// Log the elapsed time
let elapsed = NSDate().timeIntervalSinceDate(start)
print(elapsed)
以及等效的for
循环实现:
var output = [Float]()
for element in array {
output.append(element * 5)
}
平均执行时间为map
:20.1秒.for
循环的平均执行时间:11.2秒.用整数代替浮点数的结果是相似的.
我创建了一个类似的基准来测试Swift's reduce
的性能.这一次,当对一个大型数组的元素求和时,reduce
和for
个循环获得了几乎相同的性能.但当我像这样循环测试reduce
000次时:
// Populate array with 1,000,000 random numbers
var array = [Float](count: 1_000_000, repeatedValue: 0)
for i in 0..<array.count {
array[i] = Float(random())
}
let start = NSDate()
// Perform operation 100,000 times
for _ in 0..<100_000 {
let sum = array.reduce(0, combine: {$0 + $1})
}
// Log the elapsed time
let elapsed = NSDate().timeIntervalSinceDate(start)
print(elapsed)
vs:
for _ in 0..<100_000 {
var sum: Float = 0
for element in array {
sum += element
}
}
reduce
方法需要29秒,而for
循环(显然)需要0.000003秒.
当然,我准备忽略编译器优化后的最后一个测试,但我认为这可能会让我们更深入地了解编译器如何针对循环和Swift的内置数组方法进行不同的优化.请注意,所有测试都是在2.5 GHz i7 MacBook Pro上使用-Os优化进行的.结果因数组大小和迭代次数而异,但for
个循环的性能总是比其他方法至少高出1.5倍,有时甚至高达10倍.
我对Swift 在这里的表现有点困惑.在执行此类操作时,内置数组方法不应该比天真的方法更快吗?也许有人比我更了解情况.