用swift测量经过的时间

Vaq*_*ita 111 time nsdate elapsedtime swift

我们如何衡量在Swift中运行函数所用的时间?我试图像这样显示经过的时间:"Elasped time is .05 seconds".看到在Java中,我们可以使用System.nanoTime(),是否有任何等效的方法可用于Swift来实现这一目的?

请看一下示例程序:

func isPrime(var 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)) {
    println("Prime number");
} else {
    println("NOT a prime number");
}
Run Code Online (Sandbox Code Playgroud)

Jer*_*myP 197

这是我用来测量Swift中Project Euler问题的Swift函数

从Swift 3开始,现在有一个版本的Grand Central Dispatch"swiftified".所以正确的答案可能是使用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
}
Run Code Online (Sandbox Code Playgroud)

老答案

对于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
}
Run Code Online (Sandbox Code Playgroud)

请注意,不建议使用NSdate作为定时功能:" 由于与外部时间参考同步或由于时钟的明确用户更改,系统时间可能会减少. "

  • swift3对我不起作用,它返回0.0114653027,我知道这个事实不是真的,有日期的那个返回4.77720803022385sec (6认同)
  • 不幸的是.由于某种原因,正常运行时间完全消失.我有一个测试表示花了1004959766纳秒(大约一秒钟),但肯定运行了大约40秒.我在旁边使用了"Date",确实报告了41.87秒.我不知道'uptimeNanoseconds`正在做什么,但它没有报告正确的持续时间. (5认同)
  • 抱歉,进行较大的编辑会优先考虑较新的解决方案,但我什至建议您完全删除NSDate代码:使用NSDate完全不可靠:NSDate基于系统时钟,由于许多不同的原因,它可能随时更改,例如随着网络时间同步(NTP)更新时钟(通常会针对漂移进行调整),DST调整,leap秒和用户手动调整时钟。此外,您无法再使用Swift 1在AppStore上发布任何应用程序:Swift 3是最低要求。因此,除了说“不做”之外,别无保留NSDate代码。 (2认同)

Kla*_*aas 66

这是一个基于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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

let timer = ParkBenchTimer()

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

println("The task took \(timer.stop()) seconds.")
Run Code Online (Sandbox Code Playgroud)

  • 更多上下文:"重复调用此函数不保证单调增加结果.由于与外部时间参考同步或由于时钟的明确用户更改**,系统时间可能会减少**." (7认同)
  • "_重复调用此函数不保证单调增加结果."根据其[文档](https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFTimeUtils/#//apple_ref/c/FUNC/CFAbsoluteTimeGetCurrent). (4认同)

Fra*_* Yu 45

使用clock,, ProcessInfo.systemUptimeDispatchTime用于简单的启动时间.


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

基于单调时钟:

  1. ProcessInfo.systemUptime.
  2. mach_absolute_time此答案中mach_timebase_info提到的一样.
  3. clock()POSIX标准.
  4. times()POSIX标准.(太复杂了,因为我们需要考虑用户时间与系统时间,并涉及子进程.)
  5. DispatchTime (JeremyP在接受的答案中提到的围绕Mach时间API的包装器).
  6. CACurrentMediaTime().

挂钟基础:

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

  1. NSDate/ Date正如其他人所说.
  2. CFAbsoluteTime 如别人所说.
  3. DispatchWallTime.
  4. gettimeofday()POSIX标准.

备选方案1,2和3详述如下.

选项1:Foundation中的Process Info API

do {
    let info = ProcessInfo.processInfo
    let begin = info.systemUptime
    // do something
    let diff = (info.systemUptime - begin)
}
Run Code Online (Sandbox Code Playgroud)

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)
}
Run Code Online (Sandbox Code Playgroud)

diff:Double经过的时间在哪里纳秒.

选项3:POSIX时钟API

do {
    let begin = clock()
    // do something
    let diff = Double(clock() - begin) / Double(CLOCKS_PER_SEC)
}
Run Code Online (Sandbox Code Playgroud)

diff:Double以秒为单位的经过时间在哪里.

为什么不是经过时间的闹钟时间?

在文档中CFAbsoluteTimeGetCurrent:

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

原因类似于Java中的currentTimeMillisvsnanoTime:

你不能将它用于其他目的.原因是没有计算机的时钟是完美的; 它总是漂移,偶尔需要纠正.这种修正可能是手动发生的,或者在大多数机器的情况下,有一个运行的过程并不断对系统时钟("挂钟")进行小的修正.这些往往经常发生.只要有闰秒,就会发生另一次这样的修正.

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


Mau*_*ino 29

斯威夫特4最短答案:

let startingPoint = Date()
//  ... intensive task
print("\(startingPoint.timeIntervalSinceNow * -1) seconds elapsed")
Run Code Online (Sandbox Code Playgroud)

它会打印出类似于1.02107906341553秒的时间(当然时间会因任务而异,我只是向你们展示这个测量的小数精度等级).

希望它从现在开始帮助Swift 4中的某个人!

  • @MaksimKniazev 因为它是负值,所以人们想要正值! (3认同)
  • 有人能解释一下为什么 * -1 吗? (2认同)
  • @thachnb我不知道“startingPoint.timeIntervalSinceNow”会产生负值...... (2认同)
  • @MaksimKniazev Apple 说:如果日期对象早于当前日期和时间,则此属性的值为负。 (2认同)

小智 14

只需复制和粘贴此功能。用 swift 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")
    }
Run Code Online (Sandbox Code Playgroud)

使用它就像

calculateTime {
     exampleFunc()// function whose execution time to be calculated
}
Run Code Online (Sandbox Code Playgroud)


小智 13

let start = NSDate()

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

let elapsed = start.timeIntervalSinceNow

// elapsed is a negative value.
Run Code Online (Sandbox Code Playgroud)

  • abs(start.timeIntervalSinceNow)// < - 正值 (2认同)

Wit*_*ski 7

看起来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)
Run Code Online (Sandbox Code Playgroud)

遗憾的是没有提供文档,但经过一些测试后,看起来案例.nanoseconds总是被返回。

通过简单的扩展,您可以将其转换DispatchTimeIntervalTimeInterval. 信用

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Mel*_*son 6

您可以创建一个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.")
}
Run Code Online (Sandbox Code Playgroud)

此函数允许您像这样调用它time (isPrime(7)),它将返回包含结果的元组和经过时间的字符串描述.

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

  • "重复调用此函数并不能保证单调增加结果." 根据[文档](https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFTimeUtils/#//apple_ref/c/func/CFAbsoluteTimeGetCurrent). (3认同)