Mesurer le temps écoulé dans Swift

132

Comment mesurer le temps écoulé pour exécuter une fonction dans Swift? J'essaye d'afficher le temps écoulé comme ceci: "Le temps écoulé est de 0,05 seconde". Vu qu'en Java , nous pouvons utiliser System.nanoTime (), existe-t-il des méthodes équivalentes disponibles dans Swift pour y parvenir?

Veuillez consulter l'exemple de programme:

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");
}
Vaquita
la source
1
cela n'a aucun rapport avec votre problème de mesure du temps, mais la boucle peut être arrêtée au sqrt(number)lieu de number, et vous pouvez gagner un peu plus de temps - mais il y a beaucoup plus d'idées pour optimiser la recherche de nombres premiers.
holex
@holex Veuillez ignorer l'algorithme utilisé. J'essaie de comprendre comment nous pouvons mesurer le temps écoulé?
Vaquita
1
vous pouvez utiliser des NSDateobjets et mesurer la différence entre eux.
holex
4
Si vous utilisez XCode, je vous recommande d'utiliser la nouvelle fonctionnalité de test des performances. Il fait tout le gros du travail pour vous et l'exécute même plusieurs fois et vous donne le temps moyen avec son écart type ...
Roshan
1
@dumbledad Vous pouvez mesurer les performances de blocs entiers directement dans les tests unitaires. Par exemple, voyez ceci . Si vous voulez décomposer davantage une séquence (par exemple, code ligne par ligne), consultez Time Profiler qui fait partie d'Instruments. C'est beaucoup plus puissant et complet.
Roshan

Réponses:

229

Voici une fonction Swift que j'ai écrite pour mesurer les problèmes de Project Euler dans Swift

Depuis Swift 3, il existe désormais une version de Grand Central Dispatch qui est "swiftified". La bonne réponse est donc probablement d'utiliser l' API DispatchTime .

Ma fonction ressemblerait à quelque chose comme:

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

Ancienne réponse

Pour Swift 1 et 2, ma fonction utilise 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
}

Notez que l'utilisation de NSdate pour les fonctions de chronométrage est déconseillée: " L'heure système peut diminuer en raison de la synchronisation avec des références de temps externes ou en raison d'un changement d'utilisateur explicite de l'horloge. ".

JeremyP
la source
Cela semble donner de bons résultats jusqu'à environ +/- 2 microsecondes. Cependant, cela varie peut-être selon la plate-forme.
user1021430
6
swift3 ne fonctionne pas pour moi, il renvoie 0,0114653027 ce que je sais pour un fait qui n'est pas vrai, celui avec des dates renvoie 4,77720803022385sec
Cristi Băluță
5
Malheureusement non. La disponibilité est complètement terminée pour une raison quelconque. J'ai un test qui dit a pris 1004959766 nanosecondes (environ une seconde), mais fonctionnait définitivement pendant environ 40 secondes. Je l'ai utilisé à Datecôté, et bien sûr, cela rapporte 41,87 secondes. Je ne sais pas ce que uptimeNanosecondscela fait, mais cela ne rapporte pas la durée correcte.
jowie
2
Désolé pour la grande modification, donnant la priorité à votre nouvelle solution, mais je recommanderais même de supprimer complètement votre code NSDate: il est totalement peu fiable d'utiliser NSDate: NSDate est basé sur l'horloge système, qui peut changer à tout moment pour de nombreuses raisons différentes, telles que comme la synchronisation de l'heure du réseau (NTP), la mise à jour de l'horloge (il arrive souvent de s'ajuster à la dérive), les ajustements DST, les secondes intercalaires et le réglage manuel de l'horloge. De plus, vous ne pouvez plus publier sur l'AppStore aucune application utilisant Swift 1: Swift 3 est le strict minimum. Il ne sert donc à rien de conserver votre code NSDate si ce n'est de dire "ne le faites pas".
Cœur
1
@ Cœur votre critique de la version NSDate est valide (sauf que les changements DST n'affecteront pas NSDate qui est toujours en GMT), et votre modification pour inverser l'ordre est définitivement une amélioration.
JeremyP
69

Ceci est une classe de minuterie pratique basée sur 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
        }
    }
}

Vous pouvez l'utiliser comme ceci:

let timer = ParkBenchTimer()

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

println("The task took \(timer.stop()) seconds.")
Klaas
la source
4
« Les appels répétés à cette fonction ne garantissent pas des résultats à augmentation monotone », selon sa documentation .
Franklin Yu
8
Plus de contexte: "Les appels répétés à cette fonction ne garantissent pas des résultats à augmentation monotone. L'heure système peut diminuer en raison de la synchronisation avec des références de temps externes ou en raison d'un changement d'utilisateur explicite de l'horloge ."
Klaas
Le développeur doit prendre en compte la «synchronisation avec des références de temps externes» et «un changement d'utilisateur explicite de l'horloge». Voulez-vous dire qu'il est impossible que les deux situations se produisent?
Franklin Yu
@FranklinYu non, je voulais juste dire que ce sont les deux raisons possibles. Si vous comptez toujours obtenir des valeurs croissantes de manière monotone, il existe d'autres options.
Klaas
parfois je souhaite mesurer une courte période de temps; si la synchronisation se produit pendant cela, je peux me retrouver avec un temps négatif. Il y en a en fait mach_absolute_timequi ne souffre pas de ce problème, alors je me demande pourquoi celui-ci n'est pas largement connu. Peut-être simplement parce que ce n'est pas bien documenté.
Franklin Yu
54

Utilisez clock, ProcessInfo.systemUptimeou DispatchTimepour un démarrage simple.


Pour autant que je sache, il existe au moins dix façons de mesurer le temps écoulé:

Basé sur l'horloge monotone:

  1. ProcessInfo.systemUptime.
  2. mach_absolute_timeavec mach_timebase_infocomme mentionné dans cette réponse .
  3. clock()au standard POSIX .
  4. times()au standard POSIX . (Trop compliqué car nous devons considérer le temps utilisateur par rapport au temps système, et les processus enfants sont impliqués.)
  5. DispatchTime (un wrapper autour de l'API Mach time) comme mentionné par JeremyP dans la réponse acceptée.
  6. CACurrentMediaTime().

Horloge murale basée:

(ne les utilisez jamais pour les métriques: voyez ci-dessous pourquoi)

  1. NSDate/ Datecomme mentionné par d'autres.
  2. CFAbsoluteTime comme mentionné par d'autres.
  3. DispatchWallTime.
  4. gettimeofday()au standard POSIX .

Les options 1, 2 et 3 sont développées ci-dessous.

Option 1: API Process Info dans Foundation

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

diff:NSTimeIntervalest le temps écoulé en secondes.

Option 2: API Mach C

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:Doubleest le temps écoulé en nano-secondes.

Option 3: API d'horloge POSIX

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

diff:Doubleest le temps écoulé en secondes.

Pourquoi pas le temps de l'horloge murale pour le temps écoulé?

Dans la documentation de CFAbsoluteTimeGetCurrent:

Les appels répétés à cette fonction ne garantissent pas des résultats à augmentation monotone.

La raison est similaire à currentTimeMillisvs nanoTimeen Java :

Vous ne pouvez pas utiliser l'un dans l'autre but. La raison en est qu'aucune horloge d'ordinateur n'est parfaite; il dérive toujours et doit parfois être corrigé. Cette correction peut être effectuée manuellement ou, dans le cas de la plupart des machines, il existe un processus qui s'exécute et émet continuellement de petites corrections à l'horloge système ("horloge murale"). Celles-ci ont tendance à se produire souvent. Une autre correction de ce type se produit chaque fois qu'il y a une seconde intercalaire.

Ici CFAbsoluteTimefournit l'heure de l'horloge murale au lieu de l'heure de démarrage. NSDateest également l'heure de l'horloge murale.

Franklin Yu
la source
la meilleure réponse - mais quelle est la meilleure approche à adopter?!
Fattie
1
L'option 5 me convenait le mieux. Si vous envisagez un code multi-plateforme, essayez celui-ci. Les bibliothèques Darwin et Glibc ont toutes deux des clock()fonctions.
Misha Svyatoshenko
Pour les solutions System Clock: J'ai eu du succès avec ProcessInfo.processInfo.systemUptime, mach_absolute_time(), DispatchTime.now()et CACurrentMediaTime(). Mais la solution avec clock()ne se convertissait pas correctement en secondes. Je vous conseille donc de mettre à jour votre première phrase comme suit : " Utilisez ProcessInfo.systemUptime ou DispatchTime pour une heure de démarrage précise. "
Cœur
36

Réponse la plus courte de Swift 4:

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

Il vous imprimera quelque chose comme 1.02107906341553 secondes écoulées (le temps variera bien sûr en fonction de la tâche, je vous montre simplement cela pour que vous puissiez voir le niveau de précision décimal pour cette mesure).

J'espère que cela aidera quelqu'un dans Swift 4 à partir de maintenant!

Mettre à jour

Si vous voulez avoir un moyen générique de tester des parties de code, je vous suggère l'extrait suivant:

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
Mauricio Chirino
la source
Quelqu'un peut-il expliquer pourquoi * -1?
Maksim Kniazev
1
@MaksimKniazev Parce que c'est une valeur négative, les gens en veulent une positive!
thachnb
@thachnb Je n'avais aucune idée que "startingPoint.timeIntervalSinceNow" produit une valeur négative ...
Maksim Kniazev
1
@MaksimKniazev Apple dit que: Si l'objet date est antérieur à la date et à l'heure actuelles, la valeur de cette propriété est négative.
Peter Guan
13
let start = NSDate()

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

let elapsed = start.timeIntervalSinceNow

// elapsed is a negative value.
user3370455
la source
2
abs (start.timeIntervalSinceNow) // <- valeur positive
eonist
à peu près la solution la plus simple que j'ai vue, merci
MiladiuM
10

Copiez et collez simplement cette fonction. Écrit en swift 5. Copie de JeremyP ici.

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

Utilisez-le comme

calculateTime {
     exampleFunc()// function whose execution time to be calculated
}
ShaileshAher
la source
6

Vous pouvez créer une timefonction pour mesurer vos appels. Je suis inspiré par la réponse de 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.")
}

Cette fonction vous permettrait de l'appeler comme ceci, time (isPrime(7))ce qui renverrait un tuple contenant le résultat et une chaîne de description du temps écoulé.

Si vous ne souhaitez que le temps écoulé, vous pouvez le faire time (isPrime(7)).duration

Mellson
la source
3
"Les appels répétés à cette fonction ne garantissent pas des résultats à augmentation monotone." selon documentation .
Franklin Yu
3

Fonction d'aide simple pour mesurer le temps d'exécution avec fermeture.

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

Usage:

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

Résultat: #Init - execution took 1.00104497105349 seconds

Vadim Akhmerov
la source
2

vous pouvez mesurer les nanosecondes comme par exemple ceci:

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)")
holex
la source
J'ai juste exécuté ceci sans code placé dans la "// votre procédure longue", et il a donné un résultat de 240900993, qui est de 0,24 seconde.
user1021430
instancier une NSCalendarprocédure coûteuse, mais vous pouvez le faire avant de commencer à exécuter votre procédure, donc elle ne sera pas ajoutée à l'exécution de votre longue procédure ... gardez à l'esprit que l'appel de la création d'une NSDateinstance et de la –components(_:, fromDate:)méthode d' appel prend encore du temps, donc probablement vous n'obtiendrez jamais des 0.0nanosecondes.
holex
D'après l'apparence du constructeur NSCalendar, il semble qu'il ne soit pas possible de le créer à l'avance (startDate est une entrée obligatoire). C'est assez surprenant que cela semble être un tel porc.
user1021430
vous pouvez le faire (ma réponse mise à jour), le temps mesuré sans aucune procédure supplémentaire est d'environ 6.9microsecondes sur mon appareil.
holex
Cool merci. La procédure de base est désormais similaire à la réponse de JeremyP, mais le reporting est différent.
user1021430
2

J'utilise ceci:

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

Je ne sais pas si c'est plus ou moins précis que précédemment publié. Mais les secondes ont beaucoup de décimales et semblent capturer de petits changements de code dans des algorithmes comme QuickSort en utilisant swap () par rapport à l'implémentation de swap vous-même, etc.

N'oubliez pas d'augmenter vos optimisations de build lorsque vous testez les performances:

Optimisations du compilateur Swift

Peheje
la source
2

Voici mon essai pour la réponse la plus simple:

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

Remarques

  • startTimeet endTimesont du type TimeInterval, qui est juste un typealiaspour Double, il est donc facile de le convertir en un Intou autre. Le temps est mesuré en secondes avec une précision inférieure à la milliseconde.
  • Voir aussi DateInterval, qui inclut une heure de début et de fin réelle.
  • L'utilisation de l'heure depuis 1970 est similaire aux horodatages Java .
Suragch
la source
moyen le plus simple, je le voudrais en deux chaînes, la seconde est laissez elapsedTime = Date (). timeIntervalSince1970 - startTime
FreeGor
1

J'ai emprunté l'idée à Klaas de créer une structure légère pour mesurer le temps d'exécution et d'intervalle:

Utilisation du code:

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

La fonction d'arrêt n'a pas besoin d'être appelée, car la fonction d'impression donnera le temps écoulé. Il peut être appelé à plusieurs reprises pour obtenir le temps écoulé. Mais pour arrêter le chronomètre à un certain point de l'utilisation du code, timer.stop()il peut également être utilisé pour renvoyer le temps en secondes: Une let seconds = timer.stop() fois le chronomètre arrêté, le chronomètre d'intervalle ne le sera pas, de sorte que le print("Running: \(timer) ")donnera l'heure correcte même après quelques lignes de code.

Voici le code pour RunningTimer. Il est testé pour 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"}
    }
}
Sverrisson
la source
1

Enveloppez-le dans un bloc de complétion pour une utilisation facile.

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

C'est l'extrait que j'ai trouvé et il semble fonctionner pour moi sur mon Macbook avec Swift 4.

Jamais testé sur d'autres systèmes, mais j'ai pensé que cela valait la peine d'être partagé de toute façon.

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

Voici un exemple de son utilisation:

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

Une autre façon est de le faire plus explicitement:

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

C'est comme ça que je l'ai écrit.

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

Pour mesurer un algorithme, utilisez- le comme ça.

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

print("Block is running \(time) seconds.")
BilalReffas
la source
Quelle est la précision de cette heure? Parce que j'ai utilisé la minuterie avant de mettre à jour toutes les 0,1 secondes. J'ai comparé cette réponse et une avec la minuterie et le résultat de cette réponse est de 0,1 seconde plus que la minuterie ..
Maksim Kniazev
0

Classe Swift3 statique pour la synchronisation des fonctions de base. Il gardera une trace de chaque minuterie par nom. Appelez-le comme ceci au moment où vous souhaitez commencer à mesurer:

Stopwatch.start(name: "PhotoCapture")

Appelez ceci pour capturer et imprimer le temps écoulé:

Stopwatch.timeElapsed(name: "PhotoCapture")

Voici la sortie: *** PhotoCapture ms écoulé: 1402.415125 Il existe un paramètre "useNanos" si vous souhaitez utiliser nanos. N'hésitez pas à changer au besoin.

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

}

Gjchoza
la source
Tout votre travail avec mach_timebase_infoest déjà mieux implémenté que vous ne l'avez fait dans le code source de ProcessInfo.processInfo.systemUptime. Alors faites simplement watches[name] = ProcessInfo.processInfo.systemUptime. Et * TimeInterval(NSEC_PER_MSEC)si vous voulez des nanos.
Cœur
0

Basé sur la réponse de Franklin Yu et les commentaires de Cœur

Détails

  • Xcode 10.1 (10B61)
  • Swift 4.2

Solution 1

mesure(_:)

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

Utilisation de la solution 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)")
Vasily Bodnarchuk
la source
Je ne sais pas pourquoi nous aurions besoin d'utiliser des implémentations de variables. Utiliser Datepour mesurer quoi que ce soit est extrêmement déconseillé (mais systemUptimeou clock()sont OK). Quant aux tests, nous l'avons measure(_:)déjà fait.
Cœur
1
Autre remarque: pourquoi rendre la fermeture optionnelle?
Cœur
@ Cœur vous avez raison! Merci pour vos commentaires. Je mettrai à jour le message plus tard.
Vasily Bodnarchuk