Измерение прошедшего времени в swift



Как мы можем измерить время, прошедшее для запуска функции в Swift? Я пытаюсь отобразить прошедшее время следующим образом: "эластичное время есть .05 секунд". Увидел, что в Java, мы можем использовать систему.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");
}
795   16  

16 ответов:

вот быстрая функция, которую я написал для измерения Проект Эйлера проблемы в Swift

Он использует 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
}

обновление

по состоянию на Swift 3, в настоящее время существует версия Grand Central Dispatch, которая является "swifitfied". Так что новый правильный ответ, вероятно, использовать 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
}

это удобный класс таймера на основе 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.")

использовать clock,ProcessInfo.systemUptime или DispatchTime для простого запуска.


есть, насколько я знаю, по крайней мере, семь способов измерения времени:

  1. NSDate как говорили другие.
  2. CFAbsoluteTime как говорили другие.
  3. ProcessInfo.systemUptime.
  4. mach_absolute_time С mach_timebase_info как говорится в этот ответ.
  5. clock() in POSIX standard.
  6. times() на POSIX standard. (Слишком сложно, так как нам нужно для рассмотрения пользовательского времени v. s. системное время и дочерние процессы являются вовлеченный.)
  7. DispatchTime (обертка вокруг Mach time API), как упоминалось JeremyP в принятом ответе.

варианты 3, 4 и 5 подробно описаны ниже.

Вариант 3: API информации о процессе в Foundation

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

здесь diff:NSTimeInterval прошедшее время по секундам.

Вариант 4: 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 - это затраченное время на нано-секунды.

Вариант 5: POSIX clock API

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

здесь diff:Double - это затраченное время в секундах.

почему бы не Настенные часы время за истекшее время?

в документации CFAbsoluteTimeGetCurrent:

повторные вызовы этой функции не гарантируют монотонно возрастающий результаты.

причина похожа на currentTimeMillis vs nanoTime в Java:

вы не можете использовать один для другой цели. Причина в том, что нет часы компьютера идеальны; он всегда дрейфует и иногда это нужно исправить. Эта коррекция может произойти вручную, или в случае большинства машин, есть процесс, который запускает и постоянно выдает небольшие исправления в системные часы ("настенные часы.)" Эти, как правило случаться часто. Еще одна такая поправка происходит всякий раз, когда есть скачкообразная секунда.

здесь CFAbsoluteTime обеспечивает время настенных часов вместо запуска время. NSDate вероятно настенные часы время.

let start = NSDate()

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

let elapsed = start.timeIntervalSinceNow

// elapsed is a negative value.

Swift 4 самый короткий ответ:

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

он напечатает вам что-то вроде 1.02107906341553 секунд, прошедших (время, конечно, будет меняться в зависимости от задачи, я просто показываю это для вас, ребята, чтобы увидеть уровень десятичной точности для этого измерения).

надеюсь, что это поможет кому-то в Swift 4 с этого момента!

вы можете создать time функция для измерения вызовов. Меня вдохновляет Клаас' ответ.

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

вы можете измерить наносекунд как например это:

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)")

Я использую этот:

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_;
    }
}

Я не знаю, если это более или менее точный, чем выложенные ранее. Но секунды имеют много десятичных знаков и, похоже, улавливают небольшие изменения кода в алгоритмах, таких как QuickSort с использованием swap() против реализации swap urself и т. д.

Не забудьте провернуть оптимизацию сборки при тестировании производительности:

Swift compiler optimizations

простая вспомогательная функция для измерения времени выполнения с закрытием.

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

я позаимствовал идею у 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"}
    }
}

оберните его в блок завершения для удобства использования.

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

вот моя попытка для самого простого ответа:

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

Примечания

  • startTime и endTime типа TimeInterval, который просто typealias на Double, поэтому его легко преобразовать в Int или что-то еще. Время измеряется в секундах с точностью до миллисекунд.
  • см. также DateInterval, который включает в себя фактическое время начала и окончания.
  • использование времени с 1970 года является похоже на метки времени Java.

Это фрагмент я придумал, и это, кажется, работает для меня на моем 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")

вот как я это написал.

 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.")

статический класс Swift3 для базовой функции синхронизации. Он будет отслеживать каждый таймер по имени. Назовите это так в точке, которую вы хотите начать измерять:

Stopwatch.start(name: "PhotoCapture")

вызовите это, чтобы захватить и распечатать время, прошедшее:

Stopwatch.timeElapsed(name: "PhotoCapture")

это выход: *** PhotoCapture прошедшее МС: 1402.415125 Существует параметр" useNanos", если вы хотите использовать nanos. Пожалуйста, не стесняйтесь менять по мере необходимости.

   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))")
     }
  }

}

на основе Франклин Ю ответ

подробности

Xcode 9.4.1, Swift 4.1

решение

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)
    }
}

примеры использования

// Sample with Date class

var m = Measurer { Date().timeIntervalSince1970 }
var time: Any = m.measure {
    _ = (1...1000).map{_ in Int(arc4random()%100)}
}
print("Date: \(time)")

// 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()) -  ) / Double(CLOCKS_PER_SEC) }
time = m.measure {
    _ = (1...1000).map{_ in Int(arc4random()%100)}
}
print("POSIX: \(time)")

Comments

    Ничего не найдено.