在 Swift 中测量经过的时间

Posted

技术标签:

【中文标题】在 Swift 中测量经过的时间【英文标题】:Measure elapsed time in Swift 【发布时间】:2014-09-05 11:49:14 【问题描述】:

我们如何测量在 Swift 中运行一个函数所用的时间?我试图像这样显示经过的时间:“经过的时间是 0.05 秒”。看到in Java,我们可以使用 System.nanoTime(),在 Swift 中有没有等效的方法可以做到这一点?

请看示例程序:

func isPrime(_ number: Int) -> Bool 
    var i = 0;
    for i=2; i<number; i++ 
        if number % i == 0, i != 0 
            return false
        
    
    return true


var number = 5915587277

if isPrime(number) 
    print("Prime number")
 else 
    print("NOT a prime number")

【问题讨论】:

这与你的时间测量问题无关,但循环可以在sqrt(number)而不是number停止,你可以节省更多时间——但还有更多优化的想法寻找素数。 @holex 请忽略使用的算法。我想弄清楚我们如何测量经过的时间? 你可以使用NSDate对象,你可以测量它们之间的差异。 如果您使用的是 XCode,我建议您使用新的性能测试功能。它为您完成所有繁重的工作,甚至多次运行它并为您提供平均时间及其标准偏差...... @dumbledad 您可以在单元测试中直接测量整个块的性能。例如,see this。如果您想进一步分解运行(例如,逐行代码),请查看属于 Instruments 的Time Profiler。这更加强大和全面。 【参考方案1】:

这是我编写的一个 Swift 函数,用于测量 Swift 中的Project Euler 问题

从 Swift 3 开始,现在有一个“快速化”的 Grand Central Dispatch 版本。所以正确的答案可能是使用DispatchTime API。

我的函数看起来像:

// Swift 3
func evaluateProblem(problemNumber: Int, problemBlock: () -> Int) -> Answer

    print("Evaluating problem \(problemNumber)")

    let start = DispatchTime.now() // <<<<<<<<<< Start time
    let myGuess = problemBlock()
    let end = DispatchTime.now()   // <<<<<<<<<<   end time

    let theAnswer = self.checkAnswer(answerNum: "\(problemNumber)", guess: myGuess)

    let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds // <<<<< Difference in nano seconds (UInt64)
    let timeInterval = Double(nanoTime) / 1_000_000_000 // Technically could overflow for long running tests

    print("Time to evaluate problem \(problemNumber): \(timeInterval) seconds")
    return theAnswer


旧答案

对于 Swift 1 和 2,我的函数使用 NSDate:

// Swift 1
func evaluateProblem(problemNumber: Int, problemBlock: () -> Int) -> Answer

    println("Evaluating problem \(problemNumber)")

    let start = NSDate() // <<<<<<<<<< Start time
    let myGuess = problemBlock()
    let end = NSDate()   // <<<<<<<<<<   end time

    let theAnswer = self.checkAnswer(answerNum: "\(problemNumber)", guess: myGuess)

    let timeInterval: Double = end.timeIntervalSinceDate(start) // <<<<< Difference in seconds (double)

    println("Time to evaluate problem \(problemNumber): \(timeInterval) seconds")
    return theAnswer

请注意,不鼓励将 NSdate 用于计时功能:“由于与外部时间参考同步或由于用户明确更改时钟,系统时间可能会减少。”。

【讨论】:

这似乎可以提供大约 +/-2 微秒的结果。不过,这可能因平台而异。 swift3 对我不起作用,它返回 0.0114653027,我知道这是不正确的,带日期的返回 4.77720803022385sec 很遗憾没有。由于某种原因,正常运行时间完全结束。我有一个测试说花了 1004959766 纳秒(大约一秒),但肯定运行了大约 40 秒。我在旁边使用了Date,果然报告了 41.87 秒。我不知道uptimeNanoseconds 在做什么,但它没有报告正确的持续时间。 抱歉大编辑,优先考虑您的新解决方案,但我什至建议完全删除您的 NSDate 代码:使用 NSDate 完全不可靠:NSDate 基于系统时钟,可以随时更改时间由于许多不同的原因,例如网络时间同步 (NTP) 更新时钟(经常发生以调整漂移)、DST 调整、闰秒和用户手动调整时钟。此外,您不能再在 AppStore 上发布任何使用 Swift 1 的应用程序:Swift 3 是最低要求。因此,除了说“不要这样做”之外,保留您的 NSDate 代码没有任何意义。 @Cœur 您对 NSDate 版本的批评是有效的(除了 DST 更改不会影响始终在 GMT 中的 NSDate),您对颠倒顺序的编辑绝对是一种改进。【参考方案2】:

这是一个基于CoreFoundations CFAbsoluteTime的方便的计时器类:

import CoreFoundation

class ParkBenchTimer 

    let startTime:CFAbsoluteTime
    var endTime:CFAbsoluteTime?

    init() 
        startTime = CFAbsoluteTimeGetCurrent()
    

    func stop() -> CFAbsoluteTime 
        endTime = CFAbsoluteTimeGetCurrent()

        return duration!
    

    var duration:CFAbsoluteTime? 
        if let endTime = endTime 
            return endTime - startTime
         else 
            return nil
        
    

你可以这样使用它:

let timer = ParkBenchTimer()

// ... a long runnig task ...

println("The task took \(timer.stop()) seconds.")

【讨论】:

重复调用此函数并不能保证结果单调递增。”根据其documentation。 更多上下文:“重复调用此函数并不能保证结果单调递增。系统时间可能会减少由于与外部时间参考同步或由于用户明确更改时钟。” 开发人员应考虑“与外部时间参考同步”和“用户显式更改时钟”。你的意思是这两种情况不可能发生? @FranklinYu 不,我只是想说明这是两个可能的原因。如果您依赖始终获得单调递增的值,还有其他选择。 有时我想测量一段很短的时间;如果在此期间发生同步,我可能会以负时间结束。实际上有mach_absolute_time 没有遇到这个问题,所以我想知道为什么这个问题不广为人知。也许只是因为它没有很好的记录。【参考方案3】:

使用clockProcessInfo.systemUptimeDispatchTime 来简化启动时间。


据我所知,至少有十种方法可以测量经过的时间:

基于单调时钟:

    ProcessInfo.systemUptimemach_absolute_timemach_timebase_info 如this answer 中所述。 clock() in POSIX standard。 times() 在POSIX standard。 (太复杂了,因为我们需要 考虑用户时间与系统时间和子进程是 参与。) JeremyP 在接受的答案中提到的DispatchTime(马赫时间 API 的包装器)。 CACurrentMediaTime()

基于挂钟:

(永远不要将它们用于指标:见下文)

    别人提到的NSDate/DateCFAbsoluteTime 其他人提到的。 DispatchWallTimegettimeofday() 在POSIX standard。

选项 1、2 和 3 详述如下。

选项 1:Foundation 中的 Process Info API

do 
    let info = ProcessInfo.processInfo
    let begin = info.systemUptime
    // do something
    let diff = (info.systemUptime - begin)

其中diff:NSTimeInterval 是经过的时间,以秒为单位。

选项 2:Mach C API

do 
    var info = mach_timebase_info(numer: 0, denom: 0)
    mach_timebase_info(&info)
    let begin = mach_absolute_time()
    // do something
    let diff = Double(mach_absolute_time() - begin) * Double(info.numer) / Double(info.denom)

diff:Double 是经过的时间,以纳秒为单位。

选项 3:POSIX 时钟 API

do 
    let begin = clock()
    // do something
    let diff = Double(clock() - begin) / Double(CLOCKS_PER_SEC)

其中diff:Double 是经过的时间,以秒为单位。

为什么不用挂钟时间来表示经过的时间?

CFAbsoluteTimeGetCurrent的文档中:

重复调用此函数并不能保证单调 增加结果。

原因类似于currentTimeMillis vs nanoTime in Java:

您不能将其中一个用于其他目的。原因是没有 电脑时钟完美;它总是漂移,偶尔 需要纠正。这种更正可能会发生 手动,或者在大多数机器的情况下,有一个过程 运行并不断对系统时钟发出小的修正 (“挂钟”)。这些往往会经常发生。另一个这样的修正 每当有闰秒时就会发生。

这里CFAbsoluteTime 提供挂钟时间而不是启动时间 时间。 NSDate 也是挂钟时间。

【讨论】:

最好的答案 - 但是,到底什么是最好的方法呢?! 选项 5 最适合我。如果您考虑使用多平台代码,请尝试这个。 Darwin 和 Glibc 库都有 clock() 函数。 对于基于系统时钟的解决方案:我使用ProcessInfo.processInfo.systemUptimemach_absolute_time()DispatchTime.now()CACurrentMediaTime() 取得了成功。但是clock() 的解决方案没有正确转换为秒。因此,我建议您将第一句话更新为:“使用 ProcessInfo.systemUptime 或 DispatchTime 获得准确的启动时间。 很好的答案。解释了一切。 很好的答案。如果可以的话,可以使用 clock_gettime_nsec_np(CLOCK_UPTIME_RAW) 优化选项 2,它会为您进行时基转换并提供纳秒值(请参阅 manpagez.com/man/3/clock_gettime_nsec_np)【参考方案4】:

Swift 4 最短答案:

let startingPoint = Date()
//  ... intensive task
print("\(startingPoint.timeIntervalSinceNow * -1) seconds elapsed")

它会打印出类似 1.02107906341553 秒过去 的内容(当然,时间会因任务而异,我只是向你们展示此测量的小数精度级别)。

希望它从现在开始对 Swift 4 中的人有所帮助!

更新

如果你想有一个通用的方法来测试部分代码,我建议下一个 sn-p:

func measureTime(for closure: @autoclosure () -> Any) 
    let start = CFAbsoluteTimeGetCurrent()
    closure()
    let diff = CFAbsoluteTimeGetCurrent() - start
    print("Took \(diff) seconds")

用法

measureTime(for: <insert method signature here>)

控制台日志

Took xx.xxxxx seconds

【讨论】:

有人能解释为什么 * -1 吗? @MaksimKniazev 因为它是负值,所以人们想要正值! @thachnb 我不知道“startingPoint.timeIntervalSinceNow”会产生负值... @MaksimKniazev Apple 说:如果日期对象早于当前日期和时间,则该属性的值为负数。【参考方案5】:

只需复制和粘贴此功能。 5. 速写。 在此处复制 JeremyP。

func calculateTime(block : (() -> Void)) 
        let start = DispatchTime.now()
        block()
        let end = DispatchTime.now()
        let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds
        let timeInterval = Double(nanoTime) / 1_000_000_000
        print("Time: \(timeInterval) seconds")
    

像这样使用它

calculateTime 
     exampleFunc()// function whose execution time to be calculated

【讨论】:

我试图做这样的事情,但最终导致算术溢出错误!【参考方案6】:
let start = NSDate()

for index in 1...10000 
    // do nothing


let elapsed = start.timeIntervalSinceNow

// elapsed is a negative value.

【讨论】:

abs(start.timeIntervalSinceNow)// 几乎是我见过的最直接的解决方案,谢谢【参考方案7】:

您可以创建一个time 函数来衡量您的通话。 我受到Klaas' 答案的启发。

func time <A> (f: @autoclosure () -> A) -> (result:A, duration: String) 
    let startTime = CFAbsoluteTimeGetCurrent()
    let result = f()
    let endTime = CFAbsoluteTimeGetCurrent()
    return (result, "Elapsed time is \(endTime - startTime) seconds.")

这个函数允许你像time (isPrime(7))这样调用它,它会返回一个包含结果的元组和一个经过时间的字符串描述。

如果您只希望经过的时间,您可以这样做time (isPrime(7)).duration

【讨论】:

"重复调用此函数并不能保证单调递增的结果。"根据documentation.【参考方案8】:

iOS 13 似乎引入了一个新的 API 以与 DispatchTime 一起使用,从而无需手动计算两个时间戳之间的差异。

distance(to:)

let start: DispatchTime = .now()
heavyTaskToMeasure()
let duration = start.distance(to: .now())
print(duration) 
// prints: nanoseconds(NUMBER_OF_NANOSECONDS_BETWEEN_TWO_TIMESTAMPS)

遗憾的是,没有提供文档,但在进行了一些测试后,似乎总是返回 .nanoseconds 案例。

通过一个简单的扩展,您可以将DispatchTimeInterval 转换为TimeInterval。 credit

extension TimeInterval 
    init?(dispatchTimeInterval: DispatchTimeInterval) 
        switch dispatchTimeInterval 
        case .seconds(let value):
            self = Double(value)
        case .milliseconds(let value):
            self = Double(value) / 1_000
        case .microseconds(let value):
            self = Double(value) / 1_000_000
        case .nanoseconds(let value):
            self = Double(value) / 1_000_000_000
        case .never:
            return nil
        
    

【讨论】:

【参考方案9】:

用于测量闭包执行时间的简单辅助函数。

func printExecutionTime(withTag tag: String, of closure: () -> ()) 
    let start = CACurrentMediaTime()
    closure()
    print("#\(tag) - execution took \(CACurrentMediaTime() - start) seconds")

用法:

printExecutionTime(withTag: "Init") 
    // Do your work here

结果: #Init - execution took 1.00104497105349 seconds

【讨论】:

【参考方案10】:

您可以测量 纳秒,例如这个:

let startDate: NSDate = NSDate()

// your long procedure

let endDate: NSDate = NSDate()
let dateComponents: NSDateComponents = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian).components(NSCalendarUnit.CalendarUnitNanosecond, fromDate: startDate, toDate: endDate, options: NSCalendarOptions(0))
println("runtime is nanosecs : \(dateComponents.nanosecond)")

【讨论】:

我刚刚运行了这个,没有在“//你的长过程”中放置任何代码,结果为 240900993,即 0.24 秒。 实例化NSCalendar 是一个昂贵的过程,但您可以在开始运行您的过程之前执行它,因此它不会被添加到您的长过程的运行时中。 .. 请记住调用创建NSDate 实例和调用–components(_:, fromDate:) 方法仍然需要时间,所以您可能永远不会得到0.0 纳秒。 从 NSCalendar 构造函数的外观来看,似乎无法提前创建它(startDate 是必需的输入)。它似乎是这样的猪,这有点令人惊讶。 你可以这样做(我更新的答案),在我的设备上没有任何额外程序的测量时间约为 6.9 微秒。 酷,谢谢。基本程序现在类似于 JeremyP 的回答,但报告不同。【参考方案11】:

我用这个:

public class Stopwatch 
    public init()  
    private var start_: NSTimeInterval = 0.0;
    private var end_: NSTimeInterval = 0.0;

    public func start() 
        start_ = NSDate().timeIntervalSince1970;
    

    public func stop() 
        end_ = NSDate().timeIntervalSince1970;
    

    public func durationSeconds() -> NSTimeInterval 
        return end_ - start_;
    

我不知道它是否比以前发布的更准确。但是秒有很多小数,并且似乎可以捕捉到算法中的小代码更改,例如使用 swap() 的 QuickSort 与实现 swap urself 等。

记得在测试性能时加快构建优化:

【讨论】:

【参考方案12】:

这是我尝试的最简单答案:

let startTime = Date().timeIntervalSince1970  // 1512538946.5705 seconds

// time passes (about 10 seconds)

let endTime = Date().timeIntervalSince1970    // 1512538956.57195 seconds
let elapsedTime = endTime - startTime         // 10.0014500617981 seconds

备注

startTimeendTime 属于TimeInterval 类型,它只是Doubletypealias,因此很容易将其转换为Int 或其他类型。时间以秒为单位,精度为亚毫秒。 另请参阅DateInterval,其中包括实际开始和结束时间。 使用自 1970 年以来的时间类似于 Java timestamps。

【讨论】:

最简单的方法,想要两个字符串,第二个是 let elapsedTime = Date().timeIntervalSince1970 - startTime【参考方案13】:

我借鉴了 Klaas 的想法,创建了一个轻量级结构来测量跑步和间隔时间:

代码用法:

var timer = RunningTimer.init()
// Code to be timed
print("Running: \(timer) ") // Gives time interval
// Second code to be timed
print("Running: \(timer) ") // Gives final time

不必调用停止函数,因为打印函数会给出经过的时间。它可能会被重复调用以获取时间流逝。 但是要在代码中的某个点停止计时器,请使用timer.stop(),它也可以用于以秒为单位返回时间:let seconds = timer.stop() 定时器停止后,间隔定时器不会,所以print("Running: \(timer) ")即使在几行代码之后也会给出正确的时间。

以下是 RunningTimer 的代码。它已针对 Swift 2.1 进行了测试:

import CoreFoundation
// Usage:    var timer = RunningTimer.init()
// Start:    timer.start() to restart the timer
// Stop:     timer.stop() returns the time and stops the timer
// Duration: timer.duration returns the time
// May also be used with print(" \(timer) ")

struct RunningTimer: CustomStringConvertible 
    var begin:CFAbsoluteTime
    var end:CFAbsoluteTime

    init() 
        begin = CFAbsoluteTimeGetCurrent()
        end = 0
    
    mutating func start() 
        begin = CFAbsoluteTimeGetCurrent()
        end = 0
    
    mutating func stop() -> Double 
        if (end == 0)  end = CFAbsoluteTimeGetCurrent() 
        return Double(end - begin)
    
    var duration:CFAbsoluteTime 
        get 
            if (end == 0)  return CFAbsoluteTimeGetCurrent() - begin  
            else  return end - begin 
        
    
    var description:String 
    let time = duration
    if (time > 100) return " \(time/60) min"
    else if (time < 1e-6) return " \(time*1e9) ns"
    else if (time < 1e-3) return " \(time*1e6) µs"
    else if (time < 1) return " \(time*1000) ms"
    else return " \(time) s"
    

【讨论】:

【参考方案14】:

将其包装在一个完成块中以便于使用。

public class func secElapsed(completion: () -> Void) 
    let startDate: NSDate = NSDate()
    completion()
    let endDate: NSDate = NSDate()
    let timeInterval: Double = endDate.timeIntervalSinceDate(startDate)
    println("seconds: \(timeInterval)")

【讨论】:

【参考方案15】:

The recommend way 使用measure 函数来检查运行时间/性能,该函数在XCTests 中可用。

编写自己的度量块是不可靠的,因为代码块的性能(以及因此执行/经过的时间)受例如影响。 CPU 缓存。

第二次调用函数时,可能会比第一次调用更快,although it can vary a few %。因此,通过使用你自己的闭包(这里到处都给出)执行一次“基准测试”,可以得到与真实用户在生产环境中执行的代码不同的结果。

measure 函数多次调用您的代码块,模仿生产中使用的代码的性能/运行时间 (at least gives more accurate results)。

【讨论】:

【参考方案16】:

这是我想出的 sn-p,它似乎适用于我的 Macbook 和 Swift 4。

从未在其他系统上测试过,但我认为无论如何都值得分享。

typealias MonotonicTS = UInt64
let monotonic_now: () -> MonotonicTS = mach_absolute_time

let time_numer: UInt64
let time_denom: UInt64
do 
    var time_info = mach_timebase_info(numer: 0, denom: 0)
    mach_timebase_info(&time_info)
    time_numer = UInt64(time_info.numer)
    time_denom = UInt64(time_info.denom)


// returns time interval in seconds
func monotonic_diff(from: MonotonicTS, to: MonotonicTS) -> TimeInterval 
    let diff = (to - from)
    let nanos = Double(diff * time_numer / time_denom)
    return nanos / 1_000_000_000


func seconds_elapsed(since: MonotonicTS) -> TimeInterval 
    return monotonic_diff(from: since, to:monotonic_now())

这是一个如何使用它的示例:

let t1 = monotonic_now()
// .. some code to run ..
let elapsed = seconds_elapsed(since: t1)
print("Time elapsed: \(elapsed*1000)ms")

另一种方法是更明确地做到这一点:

let t1 = monotonic_now()
// .. some code to run ..
let t2 = monotonic_now()
let elapsed = monotonic_diff(from: t1, to: t2)
print("Time elapsed: \(elapsed*1000)ms")

【讨论】:

【参考方案17】:

我就是这样写的。

 func measure<T>(task: () -> T) -> Double 
        let startTime = CFAbsoluteTimeGetCurrent()
        task()
        let endTime = CFAbsoluteTimeGetCurrent()
        let result = endTime - startTime
        return result
    

要像这样使用算法来衡量它。

let time = measure 
    var array = [2,4,5,2,5,7,3,123,213,12]
    array.sorted()


print("Block is running \(time) seconds.")

【讨论】:

那个时间有多准确?因为我之前用过定时器,每 0.1 秒更新一次。我将这个答案和一个与计时器进行了比较,这个答案的结果是 0.1 秒比计时器多..【参考方案18】:

用于基本功能计时的静态 Swift3 类。它将按名称跟踪每个计时器。在你想开始测量的地方这样称呼它:

Stopwatch.start(name: "PhotoCapture")

调用它来捕获并打印经过的时间:

Stopwatch.timeElapsed(name: "PhotoCapture")

这是输出:*** PhotoCapture elapsed ms: 1402.415125 如果你想使用 nanos,有一个“useNanos”参数。 请随时根据需要进行更改。

   class Stopwatch: NSObject 

  private static var watches = [String:TimeInterval]()

  private static func intervalFromMachTime(time: TimeInterval, useNanos: Bool) -> TimeInterval 
     var info = mach_timebase_info()
     guard mach_timebase_info(&info) == KERN_SUCCESS else  return -1 
     let currentTime = mach_absolute_time()
     let nanos = currentTime * UInt64(info.numer) / UInt64(info.denom)
     if useNanos 
        return (TimeInterval(nanos) - time)
     
     else 
        return (TimeInterval(nanos) - time) / TimeInterval(NSEC_PER_MSEC)
     
  

  static func start(name: String) 
     var info = mach_timebase_info()
     guard mach_timebase_info(&info) == KERN_SUCCESS else  return 
     let currentTime = mach_absolute_time()
     let nanos = currentTime * UInt64(info.numer) / UInt64(info.denom)
     watches[name] = TimeInterval(nanos)
  

  static func timeElapsed(name: String) 
     return timeElapsed(name: name, useNanos: false)
  

  static func timeElapsed(name: String, useNanos: Bool) 
     if let start = watches[name] 
        let unit = useNanos ? "nanos" : "ms"
        print("*** \(name) elapsed \(unit): \(intervalFromMachTime(time: start, useNanos: useNanos))")
     
  

【讨论】:

您使用mach_timebase_info 的整个工作已经比在ProcessInfo.processInfo.systemUptime 的source code 中实现得更好。所以只需做watches[name] = ProcessInfo.processInfo.systemUptime。如果你想要纳米,* TimeInterval(NSEC_PER_MSEC)【参考方案19】:

基于Franklin Yu 答案和Cœur cmets

详情

Xcode 10.1 (10B61) 斯威夫特 4.2

解决方案 1

measure(_:)

解决方案 2

import Foundation

class Measurer<T: Numeric> 

    private let startClosure: ()->(T)
    private let endClosure: (_ beginningTime: T)->(T)

    init (startClosure: @escaping ()->(T), endClosure: @escaping (_ beginningTime: T)->(T)) 
        self.startClosure = startClosure
        self.endClosure = endClosure
    

    init (getCurrentTimeClosure: @escaping ()->(T)) 
        startClosure = getCurrentTimeClosure
        endClosure =  beginningTime in
            return getCurrentTimeClosure() - beginningTime
        
    

    func measure(closure: ()->()) -> T 
        let value = startClosure()
        closure()
        return endClosure(value)
    

解决方案2的使用

// Sample with ProcessInfo class

m = Measurer  ProcessInfo.processInfo.systemUptime 
time = m.measure 
    _ = (1...1000).map_ in Int(arc4random()%100)

print("ProcessInfo: \(time)")

// Sample with Posix clock API

m = Measurer(startClosure: Double(clock()))  (Double(clock()) - $0 ) / Double(CLOCKS_PER_SEC) 
time = m.measure 
    _ = (1...1000).map_ in Int(arc4random()%100)

print("POSIX: \(time)")

【讨论】:

不确定我们为什么需要使用变量实现。非常不鼓励使用Date 测量任何东西(但systemUptimeclock() 都可以)。至于测试,我们已经有measure(_:) 另一个注意事项:为什么将闭包设为可选? @Cœur 你说得对!谢谢你的cmets。我稍后会更新帖子。【参考方案20】:

类似于 C# 的 Stopwatch 类的解决方案。

用法:

let s = Stopwatch()
s.start()
    
for _ in 1..<5 
    Thread.sleep(forTimeInterval: 5)
    print("Sleeped \(s.elapsedS) S")

    
s.stop()
print("Sleeped \(s.elapsedS) s")

结果:

Sleeped 5.001374235 s
Sleeped 10.002803108 s
Sleeped 15.003942841 s
Sleeped 20.004250347000003 s
Sleeped 20.004299962 s

代码:


public class Stopwatch 
    public var elapsedS : Double 
        return elapsedMs/1000
    
    
    public var elapsedMs: Double 
        guard let startTime = startTime else  return 0 
        
        if isGoing 
            let end = DispatchTime.now()
            let nanoTime = end.uptimeNanoseconds - startTime.uptimeNanoseconds
            
            return Double(nanoTime) / 1000000
        
        
        if let endTime = endTime 
            let nanoTime = endTime.uptimeNanoseconds - startTime.uptimeNanoseconds
            return Double(nanoTime) / 1000000
        
        
        return 0
    
    
    private var startTime : DispatchTime? = nil
    private var endTime : DispatchTime? = nil
    private var isGoing = false
    
    public init ()  
    
    public func start() -> Stopwatch 
        isGoing = true
        startTime = DispatchTime.now()
        
        return self
    
    
    public func stop() 
        endTime = DispatchTime.now()
        isGoing = false
    
    
    public func printS(_ str : String? = nil)
        if let str = str 
            print("\(str): \(elapsedS)")
        
        else 
            print("\(elapsedS)")
        
    
    
    public func printMs(_ str : String? = nil)
        if let str = str 
            print("\(str): \(elapsedMs)")
        
        else 
            print("\(elapsedMs)")
        
    

【讨论】:

我的员工会对这段代码大喊大叫,请阅读 Swift 风格指南 @J.Doe 这段代码是在我开始学习 swift 的时候写的。所以在那段时间我使用了 C# 代码风格。除了代码风格之外,您对代码有任何问题吗?一切都好吗?如果是,请对其他人更有耐心:) 对 Swift Q&A 以 Swift 风格回答的要求并不高,如果每个人都以自己的风格或其他语言的风格编写 Swift,那将是一团糟。

以上是关于在 Swift 中测量经过的时间的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中测量 DispatchQueue 并发异步中的代码块执行时间?

如何在 Java 中测量经过的时间? [复制]

如何在 C# 和 C++ 中测量经过的时间

如何在 Swift 中测量 iOS 设备上的抖动量?

如何在不考虑应用程序在后台的时间的情况下测量经过的游戏时间?

如何测量代码片段的调用次数和经过时间