我需要计算2种不同算法的执行时间,然后根据执行时间确定推荐的算法。因此,对于一般的算法和数据结构,我还是很陌生,但是在Swift中却是一个新手。
所以我做了一些搜索,但没有发现太多。我确实找到了这个:
func printTimeElapsedWhenRunningCode(title:String, operation:()->()) {
let startTime = CFAbsoluteTimeGetCurrent()
operation()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed for \(title): \(timeElapsed) s.")
}
这就是我实际上要测试的内容:
printTimeElapsedWhenRunningCode(title: "Merge Sort") {
let newSort = mergeSort(sortArray)
}
现在我不确定这是否真的在计算我需要的东西。然后,每次运行此命令,我总是得到不同的时间。我是否在正确的道路上?
答案 0 :(得分:4)
注意:在现实生活中,最好找到一些已建立的性能测试框架。正确地进行测试很困难。
如果您自己进行测试,则最好不要做以下事情:
平均多次迭代,而不是一次。有很多原因导致结果有点嘈杂。如果总运行时间少于0.1秒,则很可能完全不可靠。最好是至少1秒。不仅要跟踪平均值,还要跟踪其他指标(如95%百分位数)也很有意义。
不要忽略循环内经过测试的计算结果。一个聪明的编译器可以优化未使用的结果,并用no-op之类的东西代替它。理想情况下,结果对于编译器应该不可预测。例如:在第i
次迭代中,将已排序列表的第i
个元素(或(i % array.length)
个元素)添加到总和中,最后返回总和或打印它(显然不在所计算的时间范围内)
除非要尝试测量IO操作的性能,否则请不要在经过测试的算法内进行任何打印/记录/ IO。 IO非常慢。
在主要的“测试”迭代之前进行一些热身迭代。这是为了确保可以在各种CPU缓存中存储所有数据。如果没有预热,则第一次运行和随后的运行可能会非常不同。同样,如果您正在运行托管代码(如JavaScript或Java或.Net),则许多运行可能会迫使VM重新进行代码编译,并进行一些更好的优化。在这种情况下,您可能需要先运行数千次“热身”迭代来强制执行。一些更好的测试框架会批量运行,直到不同批次之间的时间稳定为止。
将代码的优化级别与生产中使用的代码进行比较。如果允许的话,当今的编译器可以非常聪明地进行优化,并且“调试”构建的速度很容易比“发行”构建的速度慢10倍。
对于排序算法,需要记住一些特定的东西,主要是:在不同的测试阵列上进行多次测量
尝试从数个元素到数百万个元素的不同数组大小。今天的内存访问是一件非常复杂的事情。不同的算法具有不同的内存使用模式,这可能会在不同大小下极大地影响性能
检查其他数据。某些排序算法在病理上是坏情况,有些则没有。有些可能对半分类数据特别有效,而有些则无法利用它。至少使用一些随机数据。最好不仅使用随机数。
答案 1 :(得分:1)
如果您想对性能进行基准测试,则使用单元测试的measure { ... }
块是一个很好的起点,因为它会运行几次并计算经过时间,标准偏差等。
我还建议:
[Int]
而不是[String]
)进行测试,以便您专注于排序速度而不是比较速度); 但是对于快速性能测试,Xcode单元测试非常容易。例如:
class MyAppTests: XCTestCase {
let iterationCount = 1_000
// build large array
var array = (0 ..< 1_000).map { _ in Int.random(in: 0 ..< 1_000_000) }
// test performance
func testSortPerformance() {
measure {
for _ in 0 ..< iterationCount {
let results = array.sorted()
XCTAssert(!results.isEmpty)
}
}
}
func testBubbleSortPerformance() {
measure {
for _ in 0 ..< iterationCount {
let results = array.bubbleSorted()
XCTAssert(!results.isEmpty)
}
}
}
}
这将在“报表浏览器”中产生以下结果:
或者在控制台中,您将看到详细信息:
/.../MyAppTests.swift:33: Test Case '-[MyAppTests.MyAppTests testBubbleSortPerformance]' measured [Time, seconds] average: 0.603, relative standard deviation: 3.284%, values: [0.613748, 0.580443, 0.590879, 0.586842, 0.626791, 0.610288, 0.595295, 0.588713, 0.594823, 0.647156], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
/.../MyAppTests.swift:23: Test Case '-[MyAppTests.MyAppTests testSortPerformance]' measured [Time, seconds] average: 0.025, relative standard deviation: 13.393%, values: [0.033849, 0.026869, 0.022752, 0.023048, 0.023024, 0.022847, 0.023286, 0.023987, 0.023803, 0.022640], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
而且,在我尝试的同时,我也可能会自己测试排序算法,例如确保结果是增加值,并且所有项目的总和仍加起来:
func testBubbleSort() {
let results = array.bubbleSorted()
var previous = results[0]
for index in 1 ..< results.count {
let current = results[index]
XCTAssertLessThanOrEqual(previous, current)
previous = current
}
XCTAssertEqual(results.sum(), array.sum())
}