如何用Swift(beta)数组优化NSMutableArray的性能?

4
在Swift中,我正在尝试构建一个大型项目集合。在运行时创建CoreData元素时,这非常迅速。但是,在尝试保留对这些项的索引时,使用Swift创建数组会对性能产生很大影响。下面的代码是NSMutableArray和Swift Array之间的基准测试。在iOS模拟器中运行时,Swift Array慢了约8倍。为什么会这样,它可以改进吗?或者随着苹果发布新版Xcode / Swift,这种情况是否会有所改善?
代码:
var start: NSDate
var time: NSTimeInterval
var batch = 1000000
var rate: Double

var oArr = NSMutableArray(capacity: batch)
start = NSDate()
for i in 1..batch {
    oArr.addObject(i)
}
time = -start.timeIntervalSinceNow
rate = Double(batch) / Double(time)
println("NSMutableArray \(batch) appends in \(time) sec: \(rate)/sec")

var sArr = Int[]()
start = NSDate()
for i in 1..batch {
    sArr += i
}
time = -start.timeIntervalSinceNow
rate = Double(batch) / Double(time)
println("Array<Int>     \(batch) appends in \(time) sec: \(rate)/sec")

模拟器中的输出(beta 2)为794%:

NSMutableArray 1000000 appends in 1.17320102453232 sec: 852368.843096295/sec
Array<Int>     1000000 appends in 9.31138801574707 sec: 107395.374170729/sec

模拟器中的输出(beta 3):

NSMutableArray 1000000 appends in 0.71416300535202 sec: 1400240.55083487/sec
Array<Int>     1000000 appends in 5.00839000940323 sec: 199664.961818569/sec

iPhone 5上的输出(在iOS 7.1上的beta 3):

NSMutableArray 1000000 appends in 8.79256194829941 sec: 113732.494110367/sec
Array<Int>     1000000 appends in 55.6573320031166 sec: 17967.084730975/sec

1
没有什么需要修复的...只需像Objc一样编译Swift版本而不进行运行时检查。 - HAS
3
在iOS模拟器中运行时,Swift数组的速度大约比实际设备慢8倍。不要在模拟器中进行性能测试,因为这不能反映真实世界的结果。请在实际设备上运行或者在OS X(命令行)应用程序中运行。 - Jack Lawrence
1
@JackLawrence 我并不是在运行基准测试以便与其他系统进行数字比较;只是观察到 ArrayNSArray 慢得多。无论是在模拟器、iOS 设备还是 OS X 应用程序中观察到的,我都不在意。 - Bouke
没错,但评论仍然适用。数组实现可能没有针对i386 / arm sim进行优化,因为没有理由这样做。 - Jack Lawrence
@JackLawrence 请看我的更新。如预期,在设备上的性能差异与模拟器相似。 - Bouke
显示剩余3条评论
4个回答

4

更新:

在MacBook Pro 2 GHz Intel Core i7上使用Xcode beta-3和控制台程序,我使用原始测试得到以下数字(由于语法的微小变化而进行了修正):

调试模式(-O0):

NSMutableArray 1000000 appends in 0.782136023044586 sec: 1278549.9843203/sec
Array<Int>     1000000 appends in 5.56463801860809 sec: 179706.208500177/sec

Release (-Os):

NSMutableArray 1000000 appends in 0.14977502822876 sec: 6676680.43081684/sec
Array<Int>     1000000 appends in 0.124498963356018 sec: 8032195.3937913/sec

Release (-Ofast):
发布(-Ofast):
NSMutableArray 1000000 appends in 0.151567995548248 sec: 6597698.91646863/sec
Array<Int>     1000000 appends in 0.122538030147552 sec: 8160731.80543105/sec

在beta5、iOS8、iPhone 5S上,使用-Os选项:NSMutableArray 100000个追加操作用时0.0127469897270203秒:速度为7844989.45566939次/秒;[Int] 100000个追加操作用时0.053788959980011秒:速度为1859117.55938694次/秒。仍存在5倍差距 :/ - Ilya Belikin

2

你告诉 NSMutableArray 需要一次性分配多少空间,但每次添加元素时,Swift 数组都需要重新分配空间,这似乎不太公平。尽管如此,这使得 Swift 版本的速度非常快,虽然在某种程度上有些不公平:

var sArr = Array<Int>(count: batch, repeatedValue: 0)
start = NSDate()
for i in 0..batch {
    sArr[i] = i
}

编辑:看起来NSMutableArray并没有使用你提供的容量来加快自己的速度,所以也许不用在意?


这很公平,因为我希望两种实现都尽可能快。NSMutableArray提供了设置初始容量的参数。然而,您创建具有初始值的数组的建议也很有趣。虽然它不完全相同于初始容量,但表明数组也可以具有高性能。 - Bouke

1
我已经在我的旧iPhone 4上使用XCode 6.3.1进行了一些测试,并发现Array比NSMutableArray快得多。
调试模式
NSMutableArray  1000000 appends in 8.11677902936935 sec: 123201.579885525/sec
Array1<Int>     1000000 appends in 3.9488559961319 sec: 253237.900034732/sec
Array2<Int>     1000000 appends in 2.59551799297333 sec: 385279.548324162/sec

发布模式
NSMutableArray  1000000 appends in 5.76798897981644 sec: 173370.650238625/sec
Array1<Int>     1000000 appends in 0.0752439498901367 sec: 13290105.0710402/sec
Array2<Int>     1000000 appends in 0.0505729913711548 sec: 19773400.2456174/sec

当Array1 = [Int](),Array2 = [Int?](count: batch, repeatedValue: nil)时

对于Array1,我使用了array.append(i)而不是"+=",这可以使它更快。


1
Swift优化器仍在不断改进中。即使是在b1和b3之间,我也看到一个小型基准测试程序从编译为-O时需要3秒,变为只需要0.2秒。记得尝试使用-O和-Ofast选项,并在每个beta版本中继续尝试,同时对于异常或意外缓慢的事情提交错误报告。随着时间的推移,它应该会变得更好 :)

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