Lou*_*Lac 5 optimization performance branch-prediction swift
我读了着名的为什么处理排序数组比未排序数组更快?我决定玩游戏并尝试其他语言,如Swift.我对2个非常相似的代码片段之间的运行时间差异感到惊讶.
在Swift中,可以在for-in循环中以直接方式或使用下标访问数组中的元素.例如这段代码:
for i in 0..<size {
sum += data[i]
}
Run Code Online (Sandbox Code Playgroud)
可写:
for element in data {
sum += element
}
Run Code Online (Sandbox Code Playgroud)
与size所述data长度和data可累加元件的阵列.
所以,我只是在Swift(代码吼叫)中实现了与我在第一段中提到的问题相同的算法,令我惊讶的是第一种方法比第二种方法快大约5倍.
我真的不知道后台下标的实现,但我认为直接访问Swift for-in循环中的元素只是语法糖.
我的问题是两种for-in语法之间有什么区别以及为什么使用下标更快?
这里是计时器的细节.我在2015年初的MacBook Air上使用Xcode 9.4.1和Swift 4.1以及Commande Line项目.
// Using Direct Element Access
Elapsed Time: 8.506288427
Sum: 1051901000
Run Code Online (Sandbox Code Playgroud)
VS
// Using Subscript
Elapsed Time: 1.483967902
Sum: 1070388000
Run Code Online (Sandbox Code Playgroud)
奖金问题:为什么Swift中的执行速度比C++慢100倍(两者都在Xcode项目的同一台Mac上执行)?例如,C++中的100,000次重复几乎与Swift中的1,000次重复相同.我的第一个猜测是,Swift是一种比C++更高级的语言,而Swift运行更多的安全检查.
这是我使用的Swift代码,我只修改了第二个嵌套循环:
import Foundation
import GameplayKit
let size = 32_768
var data = [Int]()
var sum = 0
var rand = GKRandomDistribution(lowestValue: 0, highestValue: 255)
for _ in 0..<size {
data.append(rand.nextInt())
}
// data.sort()
let start = DispatchTime.now()
for _ in 0..<1_000 {
// Only the following for-in loop changes
for i in 0..<size {
if data[i] <= 128 {
sum += data[i]
}
}
}
let stop = DispatchTime.now()
let nanoTime = stop.uptimeNanoseconds - start.uptimeNanoseconds
let elapsed = Double(nanoTime) / 1_000_000_000
print("Elapsed Time: \(elapsed)")
print("Sum: \(sum)")
Run Code Online (Sandbox Code Playgroud)
总体性能输出很大程度上取决于编译器所做的优化.如果在启用优化的情况下编译代码,您将看到两个解决方案之间的差异很小.
为了证明这一点,我更新了你的代码,添加了两个方法,一个使用subscripting,另一个使用for-in.
import Foundation
import GameplayKit
let size = 32_768
var data = [Int]()
var sum = 0
var rand = GKRandomDistribution(lowestValue: 0, highestValue: 255)
for _ in 0..<size {
data.append(rand.nextInt())
}
// data.sort()
func withSubscript() {
let start = DispatchTime.now()
for _ in 0..<1_000 {
for i in 0..<size {
if data[i] <= 128 {
sum += data[i]
}
}
}
let stop = DispatchTime.now()
let elapsed = Double(stop.uptimeNanoseconds - start.uptimeNanoseconds) / 1_000_000_000
print("With subscript:")
print("- Elapsed Time: \(elapsed)")
print("- Sum: \(sum)")
}
func withForIn() {
let start = DispatchTime.now()
for _ in 0..<1_000 {
for element in data {
if element <= 128 {
sum += element
}
}
}
let stop = DispatchTime.now()
let elapsed = Double(stop.uptimeNanoseconds - start.uptimeNanoseconds) / 1_000_000_000
print("With for-in:")
print("- Elapsed Time: \(elapsed)")
print("- Sum: \(sum)")
}
withSubscript()
withForIn()
Run Code Online (Sandbox Code Playgroud)
我将该代码保存到一个名为的文件中array-subscripting.swift.
然后,从命令行,我们可以在没有任何优化的情况下运行它,如下所示:
$ swift array-subscripting.swift
With subscript:
- Elapsed Time: 0.924554249
- Sum: 1057062000
With for-in:
- Elapsed Time: 5.796038213
- Sum: 2114124000
Run Code Online (Sandbox Code Playgroud)
正如你在帖子中提到的,性能有很大差异.
使用优化编译代码时,这种差异可以忽略不计:
$ swiftc array-subscripting.swift -O
$ ./array-subscripting
With subscript:
- Elapsed Time: 0.110622556
- Sum: 1054578000
With for-in:
- Elapsed Time: 0.11670454
- Sum: 2109156000
Run Code Online (Sandbox Code Playgroud)
如您所见,两种解决方案都比以前更快,并且在时间执行上非常相似.
回到最初的问题,subscripting提供对内存的直接访问,这在连续数组的情况下非常有效,其中元素在内存中彼此相邻存储.
for-in 另一方面,循环从数组中创建每个元素的不可变副本,这会导致性能损失.
| 归档时间: |
|
| 查看次数: |
351 次 |
| 最近记录: |