wake-up-neo.net

Vergangene Zeit schnell messen

Wie können wir die Zeit messen, die für die Ausführung einer Funktion in Swift vergangen ist? Ich versuche, die abgelaufene Zeit wie folgt anzuzeigen: "Die abgelaufene Zeit beträgt 0,05 Sekunden". Ich habe gesehen, dass in Java wir können System.nanoTime () verwenden. Gibt es in Swift gleichwertige Methoden, um dies zu erreichen? 

Bitte sehen Sie sich das Beispielprogramm an:

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");
}
94
Vaquita

Hier ist eine Swift-Funktion, die ich geschrieben habe, um Project Euler Probleme in Swift zu messen

Ab Swift 3 gibt es jetzt eine Version von Grand Central Dispatch, die "schnell" ist. Die richtige Antwort ist also wahrscheinlich die Verwendung der DispatchTime-API .

Meine Funktion würde ungefähr so ​​aussehen:

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

Alte Antwort

Für Swift 1 und 2 verwendet meine Funktion 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
}

Beachten Sie, dass die Verwendung von NSdate für Timing-Funktionen nicht empfohlen wird: "Die Systemzeit kann aufgrund der Synchronisierung mit externen Zeitreferenzen oder aufgrund einer expliziten Benutzeränderung der Uhr abnehmen.".

176
JeremyP

Dies ist eine praktische Timer-Klasse, die auf CoreFoundations CFAbsoluteTime basiert:

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

Sie können es so verwenden:

let timer = ParkBenchTimer()

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

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

Verwenden Sie clock , ProcessInfo.systemUptime oder DispatchTime für eine einfache Inbetriebnahme.


Es gibt meines Wissens mindestens zehn Möglichkeiten, die abgelaufene Zeit zu messen:

Monotonic Clock basiert:

  1. ProcessInfo.systemUptime .
  2. mach_absolute_time mit mach_timebase_info wie in dieser antwort .
  3. clock() in POSIX-Standard .
  4. times() in POSIX-Standard . (Zu kompliziert, da wir brauchen. __, um Benutzerzeit gegenüber Systemzeit zu berücksichtigen, und untergeordnete Prozesse sind beteiligt.).
  5. DispatchTime (ein Wrapper für die Mach-Zeit-API), wie von JeremyP in akzeptierter Antwort erwähnt.
  6. CACurrentMediaTime() .

Wanduhr basiert:

(Verwenden Sie diese niemals für Metriken: siehe unten, warum)

  1. NSDate/Date wie von anderen erwähnt.
  2. CFAbsoluteTime wie von anderen erwähnt.
  3. DispatchWallTime .
  4. gettimeofday() in POSIX-Standard .

Die Optionen 1, 2 und 3 werden unten erläutert.

Option 1: Prozess-Info-API in Foundation

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

dabei ist diff:NSTimeInterval die verstrichene Zeit in Sekunden.

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

dabei ist diff:Double die verstrichene Zeit in Nanosekunden.

Option 3: POSIX-Clock-API

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

dabei ist diff:Double die verstrichene Zeit in Sekunden.

Warum keine Wanduhrzeit für abgelaufene Zeit?

In der Dokumentation von CFAbsoluteTimeGetCurrent :

Wiederholte Aufrufe dieser Funktion können nicht monoton garantiert werden steigende Ergebnisse.

Der Grund ist ähnlich zu currentTimeMillis vs. nanoTime in Java :

Sie können die eine nicht für den anderen Zweck verwenden. Der Grund ist, dass nein Computeruhr ist perfekt; es driftet immer und gelegentlich muss korrigiert werden. Diese Korrektur kann entweder passieren manuell oder bei den meisten Maschinen gibt es einen Prozess, der läuft und gibt ständig kleine Korrekturen an der Systemuhr aus ("Wanduhr"). Diese treten häufig auf. Eine weitere solche Korrektur passiert immer, wenn es eine Schaltsekunde gibt.

Hier liefert CFAbsoluteTime die Uhrzeit der Wanduhr anstelle der Uhrzeit . NSDate ist auch die Uhrzeit der Wanduhr.

37
Franklin Yu
let start = NSDate()

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

let elapsed = start.timeIntervalSinceNow

// elapsed is a negative value.
13
user3370455

Swift 4 kürzeste Antwort:

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

Es wird etwas gedruckt wie 1.02107906341553 Sekunden vergangen (Die Zeit variiert natürlich je nach Aufgabe. Ich zeige das nur, damit Sie die Dezimalgenauigkeit für diese Messung sehen können).

Hoffe, es hilft jetzt jemandem in Swift 4!

11

Sie könnten eine time-Funktion erstellen, um Ihre Anrufe zu messen ..__ Ich bin von Klaas ' answer inspiriert.

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

Mit dieser Funktion können Sie es wie folgt time (isPrime(7)) aufrufen, wodurch ein Tuple mit dem Ergebnis und einer Zeichenfolge-Beschreibung der verstrichenen Zeit zurückgegeben wird.

Wenn Sie nur die verstrichene Zeit wünschen, können Sie dies tun time (isPrime(7)).duration

6
Mellson

Kopieren Sie einfach diese Funktion und fügen Sie sie ein. Geschrieben in Swift 5. Kopieren von JeremyP hier.

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

Benutze es wie

calculateTime {
     exampleFunc()// function whose execution time to be calculated
}
2
ShaileshAher

Hier ist mein Versuch für die einfachste Antwort:

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

Anmerkungen

  • startTime und endTime sind vom Typ TimeInterval , was nur eine typealias für Double ist, daher ist es leicht, sie in eine Int oder was auch immer zu konvertieren. Die Zeit wird in Sekunden mit einer Genauigkeit von unter einer Millisekunde gemessen.
  • Siehe auch DateInterval , die eine tatsächliche Start- und Endzeit enthält.
  • Die Verwendung der Zeit seit 1970 ist ähnlich wie Java-Zeitstempel .
2
Suragch

Einfache Hilfsfunktion zur Messung der Ausführungszeit mit Schließung.

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

Verwendungszweck:

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

Ergebnis: #Init - execution took 1.00104497105349 seconds

2
Vadim Akhmerov

Ich benutze das:

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

Ich weiß nicht, ob es mehr oder weniger genau ist als zuvor veröffentlicht. Aber die Sekunden haben viele Dezimalzahlen und scheinen kleine Codeänderungen in Algorithmen wie QuickSort mit swap () gegenüber der Implementierung von swap urself usw. zu erkennen.

Vergessen Sie nicht, Ihre Buildoptimierungen zu testen, wenn Sie die Leistung testen:

Swift compiler optimizations

2
Peheje

sie können die Nanosekunden wie z. diese:

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

Wickeln Sie es zur einfachen Verwendung in einen Abschlussblock ein.

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

Ich habe mir die Idee von Klaas geliehen, eine leichte Struktur zur Messung der Lauf- und Intervallzeit zu erstellen:

Code-Verwendung:

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

Die Stoppfunktion muss nicht aufgerufen werden, da die Druckfunktion die verstrichene Zeit angibt. Es kann wiederholt aufgerufen werden, um die abgelaufene Zeit zu erhalten. Um den Timer an einem bestimmten Punkt im Code zu stoppen, können Sie mit timer.stop() auch die Zeit in Sekunden zurückgeben: let seconds = timer.stop() Nach dem Stopp des Timers wird der Intervalltimer nicht ausgeführt , so dass die Funktion print("Running: \(timer) ") auch nach einigen Codezeilen die korrekte Zeit angibt.

Im Folgenden finden Sie den Code für RunningTimer. Es wurde für Swift 2.1 getestet:

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

Dies ist der Ausschnitt, den ich mir ausgedacht habe und er scheint auf meinem Macbook mit Swift 4 zu funktionieren.

Noch nie auf anderen Systemen getestet, aber ich dachte, es lohnt sich trotzdem, es zu teilen.

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

Hier ist ein Beispiel, wie man es benutzt:

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

Eine andere Möglichkeit besteht darin, es expliziter zu machen:

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

Basierend auf Franklin Yu answer und Cœur comments

Einzelheiten

  • Xcode 10,1 (10B61)
  • Schnell 4.2

Lösung 1

messen(_:)

Lösung 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)
    }
}

Verwendung von Lösung 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)")
0

So habe ich es geschrieben. 

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

Um einen Algorithmus use zu messen, ist es so. 

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

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

Statische Swift3-Klasse für das Timing der Basisfunktionen. Es verfolgt jeden Timer nach Namen. Nennen Sie es an der Stelle, an der Sie mit der Messung beginnen möchten:

Stopwatch.start(name: "PhotoCapture")

Rufen Sie dies auf, um die abgelaufene Zeit zu erfassen und auszudrucken:

Stopwatch.timeElapsed(name: "PhotoCapture")

Dies ist die Ausgabe: *** PhotoCapture abgelaufen ms: 1402.415125 Es gibt einen "useNanos" -Parameter, wenn Sie nanos . Verwenden möchten.

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

}

0
Gjchoza