Misura il tempo trascorso in Swift


132

Come possiamo misurare il tempo trascorso per eseguire una funzione in Swift? Sto cercando di visualizzare il tempo trascorso in questo modo: "Il tempo trascorso è di 0,05 secondi". Visto che in Java , possiamo usare System.nanoTime (), ci sono metodi equivalenti disponibili in Swift per ottenere questo risultato?

Dai un'occhiata al programma di esempio:

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

1
non è correlato al tuo problema di misurazione del tempo, ma il ciclo può essere interrotto sqrt(number)invece di number, e puoi risparmiare un po 'più di tempo - ma ci sono molte più idee che ottimizzano la ricerca di numeri primi.
Holex,

@holex Si prega di ignorare l'algoritmo utilizzato. Sto cercando di capire come possiamo misurare il tempo trascorso?
Vaquita,

1
puoi usare NSDateoggetti e puoi misurare la differenza tra loro.
Holex,

4
Se si utilizza XCode, si consiglia di utilizzare la nuova funzionalità di test delle prestazioni. Fa tutto il sollevamento pesante per te e lo esegue anche più volte e ti dà il tempo medio con la sua deviazione standard ...
Roshan

1
@dumbledad È possibile misurare le prestazioni di interi blocchi direttamente nei test unitari. Ad esempio, vedi questo . Se vuoi interrompere ulteriormente una corsa (diciamo, codice riga per riga), controlla Time Profiler che fa parte di Instruments. Questo è molto più potente e completo.
Roshan,

Risposte:


229

Ecco una funzione Swift che ho scritto per misurare i problemi di Project Euler in Swift

A partire da Swift 3, ora esiste una versione di Grand Central Dispatch che è "modificata". Quindi la risposta corretta è probabilmente usare l' API DispatchTime .

La mia funzione sarebbe simile a:

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

Vecchia risposta

Per Swift 1 e 2, la mia funzione utilizza 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
}

Si noti che l'utilizzo di NSdate per le funzioni di temporizzazione è sconsigliato: " L'ora del sistema può diminuire a causa della sincronizzazione con riferimenti temporali esterni o a causa di un esplicito cambio dell'orologio da parte dell'utente ".


Questo sembra dare risultati buoni fino a circa +/- 2microsec. Forse ciò varia in base alla piattaforma, tuttavia.
user1021430

6
swift3 non funziona per me, restituisce 0,0114653027 che conosco per un fatto che non è vero, quello con le date restituisce 4.77720803022385sec
Cristi Băluță

5
Sfortunatamente no. Il tempo di attività è completamente esaurito per qualche motivo. Ho un test che dice che ha impiegato 1004959766 nanosecondi (circa un secondo), ma è stato sicuramente in esecuzione per circa 40 secondi. Ho usato a Datefianco, e abbastanza sicuro che riporta 41,87 secondi. Non so cosa uptimeNanosecondsstia facendo, ma non sta segnalando la durata corretta.
jowie,

2
Ci scusiamo per la grande modifica, dando la priorità alla tua soluzione più recente, ma consiglierei anche di eliminare del tutto il tuo codice NSDate: è totalmente inaffidabile utilizzare NSDate: NSDate si basa sull'orologio di sistema, che può cambiare in qualsiasi momento a causa di molte ragioni diverse, come come sincronizzazione dell'ora di rete (NTP) che aggiorna l'orologio (spesso accade per regolare la deriva), regolazioni dell'ora legale, secondi saltanti e regolazione manuale dell'utente dell'orologio. Inoltre, non è più possibile pubblicare sull'AppStore alcuna app che utilizza Swift 1: Swift 3 è il minimo indispensabile. Quindi non ha senso conservare il codice NSDate se non quello di dire "non farlo".
Cuor

1
@ Cœur le tue critiche alla versione di NSDate sono valide (tranne che le modifiche all'ora legale non influiranno su NSDate che è sempre in GMT) e la tua modifica per invertire l'ordine è sicuramente un miglioramento.
JeremyP,

69

Questa è una comoda classe di timer basata su 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
        }
    }
}

Puoi usarlo in questo modo:

let timer = ParkBenchTimer()

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

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

4
" Le chiamate ripetute a questa funzione non garantiscono risultati monotonicamente crescenti ", secondo la sua documentazione .
Franklin Yu,

8
Altro contesto: "Le chiamate ripetute a questa funzione non garantiscono risultati monotonicamente crescenti. L'ora del sistema può diminuire a causa della sincronizzazione con riferimenti temporali esterni o a causa di un esplicito cambio dell'orologio da parte dell'utente ."
Klaas,

Lo sviluppatore dovrebbe tenere conto della "sincronizzazione con riferimenti temporali esterni" e "una modifica esplicita dell'orologio da parte dell'utente". Intendevi dire che è impossibile che si verifichino le due situazioni?
Franklin Yu,

@FranklinYu no, volevo solo affermare che queste sono le due possibili ragioni. Se fai affidamento sull'ottenere sempre valori monotonicamente crescenti ci sono altre opzioni.
Klaas,

a volte desidero misurare un breve periodo di tempo; se la sincronizzazione avviene durante questo, potrei finire con un tempo negativo. In realtà c'è mach_absolute_timechi non soffre di questo problema, quindi mi chiedo perché quello non sia ampiamente conosciuto. Forse solo perché non è ben documentato.
Franklin Yu,

54

Utilizzare clock, ProcessInfo.systemUptimeo DispatchTimeper un semplice tempo di avvio.


Per quanto ne so, esistono almeno dieci modi per misurare il tempo trascorso:

Basato su orologio monotonico:

  1. ProcessInfo.systemUptime.
  2. mach_absolute_timecon mach_timebase_infocome menzionato in questa risposta .
  3. clock()nello standard POSIX .
  4. times()nello standard POSIX . (Troppo complicato poiché dobbiamo considerare il tempo dell'utente rispetto al tempo di sistema e sono coinvolti i processi figlio.)
  5. DispatchTime (un wrapper attorno all'API di Mach Time) come indicato da JeremyP nella risposta accettata.
  6. CACurrentMediaTime().

Basato su orologio da parete:

(non usare mai quelli per le metriche: vedi sotto perché)

  1. NSDate/ Datecome menzionato da altri.
  2. CFAbsoluteTime come menzionato da altri.
  3. DispatchWallTime.
  4. gettimeofday()nello standard POSIX .

Le opzioni 1, 2 e 3 sono elaborate di seguito.

Opzione 1: API delle informazioni di processo in Foundation

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

dove diff:NSTimeIntervalè il tempo trascorso in secondi.

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

dove diff:Doubleè il tempo trascorso di nano-secondi.

Opzione 3: API dell'orologio POSIX

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

dove diff:Doubleè il tempo trascorso in secondi.

Perché non l'ora dell'orologio da parete per il tempo trascorso?

Nella documentazione di CFAbsoluteTimeGetCurrent:

Le chiamate ripetute a questa funzione non garantiscono risultati monotonicamente crescenti.

Il motivo è simile a currentTimeMillisvs nanoTimein Java :

Non puoi usare l'uno per l'altro scopo. Il motivo è che nessun orologio da computer è perfetto; va sempre alla deriva e occasionalmente deve essere corretto. Questa correzione può avvenire manualmente o, nel caso della maggior parte delle macchine, esiste un processo che viene eseguito e genera continuamente piccole correzioni all'orologio di sistema ("orologio da parete"). Questi tendono ad accadere spesso. Un'altra correzione di questo tipo si verifica ogni volta che c'è un secondo di salto.

Qui CFAbsoluteTimefornisce l'ora dell'orologio da parete anziché l'ora di avvio. NSDateè anche l'ora dell'orologio da parete.


la risposta migliore - ma quale diavolo è l'approccio migliore da adottare ?!
Fattie,

1
Opzione 5 più adatta a me. Se stai considerando il codice multipiattaforma prova questo. Entrambe le librerie Darwin e Glibc hanno una clock()funzione.
Misha Svyatoshenko,

Per le soluzioni basate su System Clock: ho avuto successo con ProcessInfo.processInfo.systemUptime, mach_absolute_time(), DispatchTime.now()e CACurrentMediaTime(). Ma la soluzione con clock()non stava convertendo correttamente in secondi. Quindi consiglierei di aggiornare la tua prima frase a: " Usa ProcessInfo.systemUptime o DispatchTime per un orario di avvio accurato. "
Cœur

36

Swift 4 risposta più breve:

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

Ti stamperà qualcosa come 1.02107906341553 secondi trascorsi (il tempo ovviamente varierà a seconda del compito, lo sto solo mostrando a voi ragazzi per vedere il livello di precisione decimale per questa misura).

Spero che d'aiuto qualcuno in Swift 4 d'ora in poi!

Aggiornare

Se vuoi avere un modo generico di testare porzioni di codice, suggerirei il frammento seguente:

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

*Usage*

measureTime(for: <insert method signature here>)

**Console log**
Took xx.xxxxx seconds

Qualcuno può spiegare perché * -1?
Maksim Kniazev,

1
@MaksimKniazev Perché è un valore negativo, la gente ne vuole uno positivo!
Thachnb,

@thachnb Non avevo idea che "startingPoint.timeIntervalSinceNow" producesse un valore negativo ...
Maksim Kniazev,

1
@MaksimKniazev Apple afferma che: Se l'oggetto data è precedente alla data e all'ora correnti, il valore di questa proprietà è negativo.
Peter Guan,

13
let start = NSDate()

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

let elapsed = start.timeIntervalSinceNow

// elapsed is a negative value.

2
abs (start.timeIntervalSinceNow) // <- valore positivo
eonista

praticamente la soluzione più semplice che abbia mai visto, grazie
MiladiuM,

10

Basta copiare e incollare questa funzione. Scritto in rapido 5. Copia qui 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")
    }

Usalo come

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

6

È possibile creare una timefunzione per misurare le chiamate. Sono ispirato dalla risposta di 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.")
}

Questa funzione ti permetterebbe di chiamarla così time (isPrime(7))che restituirebbe una tupla contenente il risultato e una descrizione della stringa del tempo trascorso.

Se desideri solo il tempo trascorso, puoi farlo time (isPrime(7)).duration


3
"Le chiamate ripetute a questa funzione non garantiscono risultati monotonicamente crescenti." secondo la documentazione .
Franklin Yu,

3

Semplice funzione di supporto per misurare i tempi di esecuzione con chiusura.

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

Uso:

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

Risultato: #Init - execution took 1.00104497105349 seconds


2

puoi misurare i nanosecondi come ad esempio questo:

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

Ho appena eseguito questo senza alcun codice inserito nella "// tua lunga procedura", e ha dato un risultato di 240900993, che è 0,24 secondi.
user1021430

creare un'istanza NSCalendarè una procedura costosa, ma è possibile farlo prima di iniziare a eseguire la procedura, quindi non verrà aggiunta al runtime della procedura lunga ... tenere presente che la creazione di NSDateun'istanza e il –components(_:, fromDate:)metodo di chiamata richiedono ancora tempo, quindi probabilmente non otterrai mai 0.0nanosecondi.
Holex,

Dall'aspetto del costruttore NSCalendar, sembra che potrebbe non essere possibile crearlo in anticipo (startDate è un input richiesto). È un po 'sorprendente che sembra essere un tale maiale.
user1021430

puoi farlo (la mia risposta aggiornata), il tempo misurato senza alcuna procedura aggiuntiva è di circa 6.9microsecondi sul mio dispositivo.
Holex,

Figo, grazie. La procedura di base è ora simile alla risposta di JeremyP, ma la segnalazione è diversa.
user1021430

2

Io lo uso questo:

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

Non so se sia più o meno preciso di quanto precedentemente pubblicato. Ma i secondi hanno molti decimali e sembrano catturare piccole modifiche al codice in algoritmi come QuickSort usando swap () rispetto all'implementazione di swap noi stessi ecc.

Ricorda di aumentare le ottimizzazioni di build durante il test delle prestazioni:

Ottimizzazioni rapide del compilatore


2

Ecco il mio tentativo per la risposta più semplice:

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

Appunti

  • startTimee endTimesono del tipo TimeInterval, che è solo un typealiasa Double, quindi è facile convertirlo in uno Into qualunque cosa. Il tempo viene misurato in secondi con precisione inferiore al millisecondo.
  • Vedi anche DateInterval, che include l'ora di inizio e di fine effettiva.
  • L'uso del tempo dal 1970 è simile ai timestamp Java .

il modo più semplice, lo vorrebbe in due stringhe, il secondo è lasciare passare il tempo trascorso = Date (). timeIntervalSince1970 - startTime
FreeGor

1

Ho preso in prestito l'idea di Klaas per creare una struttura leggera per misurare il tempo di corsa e di intervallo:

Utilizzo del codice:

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

Non è necessario chiamare la funzione di arresto, poiché la funzione di stampa indica il tempo trascorso. Può essere chiamato ripetutamente per far scadere il tempo. Ma per fermare il timer ad un certo punto nell'uso del codice timer.stop(), può anche essere usato per restituire il tempo in secondi: let seconds = timer.stop() Dopo che il timer è stato arrestato, l'intervallo non lo farà, quindi print("Running: \(timer) ")fornirà l'ora corretta anche dopo alcune righe di codice.

Di seguito è riportato il codice per RunningTimer. È testato per 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"}
    }
}

1

Avvolgilo in un blocco di completamento per un facile utilizzo.

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

0

Questo è lo snippet che mi è venuto in mente e sembra funzionare per me sul mio Macbook con Swift 4.

Non ho mai provato su altri sistemi, ma ho pensato che valesse comunque la pena condividerli.

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

Ecco un esempio di come usarlo:

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

Un altro modo è farlo in modo più esplicito:

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

È così che l'ho scritto.

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

Per misurare un algoritmo usalo in quel modo.

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

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

Quanto è preciso quel tempo? Perché ho usato il timer prima di aggiornare ogni 0,1 secondi. Ho confrontato questa risposta e una con il timer e il risultato di questa risposta è 0,1 secondi è più che con il timer ..
Maksim Kniazev

0

Classe Swift3 statica per i tempi delle funzioni di base. Terrà traccia di ciascun timer per nome. Chiamalo così nel punto in cui vuoi iniziare a misurare:

Stopwatch.start(name: "PhotoCapture")

Chiamalo per catturare e stampare il tempo trascorso:

Stopwatch.timeElapsed(name: "PhotoCapture")

Questo è l'output: *** PhotoCapture trascorso ms: 1402.415125 Esiste un parametro "useNanos" se si desidera utilizzare nanos. Sentiti libero di cambiare se necessario.

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

}


Tutto il tuo lavoro con mach_timebase_infoè già implementato meglio di quanto hai fatto nel codice sorgente di ProcessInfo.processInfo.systemUptime. Quindi semplicemente watches[name] = ProcessInfo.processInfo.systemUptime. E * TimeInterval(NSEC_PER_MSEC)se vuoi i nanos.
Cuor

0

Basato sulla risposta di Franklin Yu e sui commenti del Cœur

Dettagli

  • Xcode 10.1 (10B61)
  • Rapido 4.2

Soluzione 1

misurare(_:)

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

Utilizzo della soluzione 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)")

Non sono sicuro del motivo per cui dovremmo utilizzare implementazioni variabili. L'uso Dateper misurare qualsiasi cosa è estremamente scoraggiato (ma systemUptimeo va clock()bene). Per quanto riguarda i test, abbiamo measure(_:)già.
Cuor

1
Un'altra nota: perché rendere opzionale la chiusura?
Cuor

@ Cœur hai ragione! Grazie per i tuoi commenti Aggiornerò post più tardi.
Vasily Bodnarchuk,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.