除了以下方法,是否有一种方法/软件可以给出编写在Swift中的代码块所需的精确时间?
let date_start = NSDate()
// Code to be executed
println("\(-date_start.timeIntervalSinceNow)")
除了以下方法,是否有一种方法/软件可以给出编写在Swift中的代码块所需的精确时间?
let date_start = NSDate()
// Code to be executed
println("\(-date_start.timeIntervalSinceNow)")
如果你只是想为一块代码使用独立的计时函数,我使用以下的Swift辅助函数:
func printTimeElapsedWhenRunningCode(title:String, operation:()->()) {
let startTime = CFAbsoluteTimeGetCurrent()
operation()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed for \(title): \(timeElapsed) s.")
}
func timeElapsedInSecondsWhenRunningCode(operation: ()->()) -> Double {
let startTime = CFAbsoluteTimeGetCurrent()
operation()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
return Double(timeElapsed)
}
前者将记录给定代码部分所需的时间,后者将其作为浮点数返回。以下是第一种变体的示例:
printTimeElapsedWhenRunningCode(title:"map()") {
let resultArray1 = randoms.map { pow(sin(CGFloat($0)), 10.0) }
}
将记录类似以下内容:
map() 执行的时间:0.0617449879646301 秒
请注意,Swift 基准测试的结果会严重受到所选优化级别的影响,因此这只对比较 Swift 执行时间有用。即使如此,在每个测试版中,结果可能也会发生变化。
measure(_ block: () -> Void)
。func testExample() {
self.measure {
//do something you want to measure
}
}
您可以在苹果文档中找到更多信息,具体位置为使用Xcode进行测试 -> 性能测试。
measureBlock
会多次执行代码块以获取更好的统计数据。 - Eneko AlonsomeasureBlock
是什么?它来自哪里(我应该导入什么)?在Swift 4中。 - user924import Foundation
func measure(_ title: String, block: (@escaping () -> ()) -> ()) {
let startTime = CFAbsoluteTimeGetCurrent()
block {
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("\(title):: Time: \(timeElapsed)")
}
}
基本上你需要传递一个接受函数作为参数的块,用于告诉 measure 何时完成。
例如,要测量名为“myAsyncCall”的某个调用需要多长时间,您可以像这样调用它:
measure("some title") { finish in
myAsyncCall {
finish()
}
// ...
}
对于同步代码:
measure("some title") { finish in
// code to benchmark
finish()
// ...
}
这应该与 XCTest 的 measureBlock 类似,虽然我不知道它在那里是如何实现的。
这是一个非常通用的基准测试功能,允许对测试进行标记,执行多个测试并平均它们的执行时间,在测试之间调用设置块(即在测量数组排序算法之间洗牌数组),清晰地打印基准测试结果,并将平均执行时间作为Double
返回。
尝试以下内容:
@_transparent @discardableResult public func measure(label: String? = nil, tests: Int = 1, printResults output: Bool = true, setup: @escaping () -> Void = { return }, _ block: @escaping () -> Void) -> Double {
guard tests > 0 else { fatalError("Number of tests must be greater than 0") }
var avgExecutionTime : CFAbsoluteTime = 0
for _ in 1...tests {
setup()
let start = CFAbsoluteTimeGetCurrent()
block()
let end = CFAbsoluteTimeGetCurrent()
avgExecutionTime += end - start
}
avgExecutionTime /= CFAbsoluteTime(tests)
if output {
let avgTimeStr = "\(avgExecutionTime)".replacingOccurrences(of: "e|E", with: " × 10^", options: .regularExpression, range: nil)
if let label = label {
print(label, "▿")
print("\tExecution time: \(avgTimeStr)s")
print("\tNumber of tests: \(tests)\n")
} else {
print("Execution time: \(avgTimeStr)s")
print("Number of tests: \(tests)\n")
}
}
return avgExecutionTime
}
var arr = Array(1...1000).shuffled()
measure(label: "Map to String") {
let _ = arr.map { String($0) }
}
measure(label: "Apple's Sorting Method", tests: 1000, setup: { arr.shuffle() }) {
arr.sort()
}
measure {
let _ = Int.random(in: 1...10000)
}
let mathExecutionTime = measure(printResults: false) {
let _ = 219 * 354
}
print("Math Execution Time: \(mathExecutionTime * 1000)ms")
// Prints:
//
// Map to String ▿
// Execution time: 0.021643996238708496s
// Number of tests: 1
//
// Apple's Sorting Method ▿
// Execution time: 0.0010601345300674438s
// Number of tests: 1000
//
// Execution time: 6.198883056640625 × 10^-05s
// Number of tests: 1
//
// Math Execution Time: 0.016927719116210938ms
//
注意:measure
函数还返回执行时间。参数label
,tests
和setup
是可选的。参数printResults
默认为true
。
func myFunction(args: Int...) {
// Do something
}
func testMyFunction() -> String {
// Wrap the call to myFunction here, and optionally test with different arguments
myFunction(args: 1, 2, 3)
return #function
}
// Measure average time to complete test
func averageTimeTo(_ testFunction: () -> String, repeated reps: UInt = 10) -> Double {
let functionName = testFunction()
var totalTime = 0.0
for _ in 0..<reps {
let startTime = CFAbsoluteTimeGetCurrent()
testFunction()
let elapsedTime = CFAbsoluteTimeGetCurrent() - startTime
totalTime += elapsedTime
}
let averageTime = totalTime / Double(reps)
print("Total time to \(functionName) \(reps) times: \(totalTime) seconds")
print("Average time to \(functionName): \(averageTime) seconds\n")
return averageTime
}
averageTimeTo(testMyFunction)
// Total time to testMyFunction() 10 times: 0.000253915786743164 seconds
// Average time to testMyFunction(): 2.53915786743164e-05 seconds
averageTimeTo(testMyFunction, repeated: 1000)
// Total time to testMyFunction() 1000 times: 0.027538537979126 seconds
// Average time to testMyFunction(): 2.7538537979126e-05 seconds
averageTime
,因此@discardableResult
可能会很有用。 - ielyamani对 @Brad Larson 的回答(被采纳的答案)进行小幅度改进,以允许函数如果需要返回操作结果。
@discardableResult func printTimeElapsedWhenRunningCode<T>(title: String, operation: () -> T) -> T {
let startTime = CFAbsoluteTimeGetCurrent()
let result = operation()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed for \(title): \(timeElapsed) s.")
return result
}
基准测试Swift代码执行
请在Production
构建上进行基准测试,而不是Debug
,因为它包含更多的优化。
你有几种可能性
DispatchTime.now().uptimeNanoseconds
(并除以1_000_000)
基于机器绝对时间单位
壁钟(由于闰秒或其他微小修正,不推荐使用)
Date().timeIntervalSince1970
CFAbsoluteTimeGetCurrent
测试
let metrics: [XCTMetric] = [XCTMemoryMetric(), XCTStorageMetric(), XCTClockMetric()]
let measureOptions = XCTMeasureOptions.default
measureOptions.iterationCount = 3
measure(metrics: metrics, options: measureOptions) {
//block of code
}
measure
块的通用函数,因为Xcode有时无法正确处理它。这就是为什么应该针对每个性能测试使用measure
块的原因。Measure.start("create-user")
let user = User()
Measure.finish("create-user")
控制台输出:
⏲ Measure [create-user]: 0.00521 sec.
测量异步请求
Measure.start("request")
let url = URL(string: "https://httpbin.org/get")!
URLSession.shared.dataTask(with: url) { _, _, _ in
let time = Measure.finish("request")
Analytics.send(event: "Request", ["time" => time])
}.resume()
完整包的代码:
// Mezhevikin Alexey: https://github.com/mezhevikin/Measure
import Foundation
public class Measure {
static private var starts = [String: Double]()
static public func start(_ key: String) {
starts[key] = CFAbsoluteTimeGetCurrent()
}
@discardableResult
static public func finish(_ key: String) -> Double {
guard let start = starts[key] else {
print(" Key [\(key)] not found")
return 0
}
let time = CFAbsoluteTimeGetCurrent() - start
print(String(format: "⏲ Measure [\(key)]: %.5f sec.", time))
starts.removeValue(forKey: key)
return time
}
}
class TimeMeasurement {
static var shared: TimeMeasurement = TimeMeasurement()
private var start = CFAbsoluteTimeGetCurrent()
func begin() {
start = CFAbsoluteTimeGetCurrent()
}
@discardableResult func end() -> Double {
let diff = CFAbsoluteTimeGetCurrent() - start
print("Took \(diff) seconds")
return diff
}
}