Comment pouvons-nous mesurer le temps écoulé pour exécuter une fonction dans Swift? J'essaie d'afficher le temps écoulé comme ceci: "Le temps imparti est de 0,05 seconde". Vu que en Java , nous pouvons utiliser System.nanoTime (), existe-t-il des méthodes équivalentes? Des méthodes sont disponibles dans Swift pour accomplir cela.
S'il vous plaît jeter un oeil à 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");
}
Voici une fonction Swift que j'ai écrite pour mesurer Project Euler problèmes dans Swift
Depuis Swift 3, il existe maintenant une version de Grand Central Dispatch qui est "accélérée". 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
}
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 minutage est déconseillée: "L’heure du système peut diminuer en raison de la synchronisation avec des références de temps externes ou du changement explicite de l’horloge par l’utilisateur.".
Il s'agit d'une classe de minuteur pratique basée sur CoreFoundation
s 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.")
clock
, ProcessInfo.systemUptime
ou DispatchTime
pour une heure de démarrage simple.À ma connaissance, il existe au moins dix façons de mesurer le temps écoulé:
ProcessInfo.systemUptime
.mach_absolute_time
avec mach_timebase_info
comme indiqué dans this answer .clock()
in POSIX standard .times()
in POSIX standard . (Trop compliqué car nous avons besoin. De prendre en compte le temps utilisateur par rapport au temps système, et les processus enfants sont impliqués.).DispatchTime
(un wrapper autour de l'API de temps Mach) tel que mentionné par JeremyP dans la réponse acceptée.CACurrentMediaTime()
.(n'utilisez jamais ceux-ci pour les métriques: voir ci-dessous pourquoi)
NSDate
/Date
comme mentionné par d'autres.CFAbsoluteTime
comme mentionné par d'autres.DispatchWallTime
.gettimeofday()
in POSIX standard .Les options 1, 2 et 3 sont détaillées ci-dessous.
do {
let info = ProcessInfo.processInfo
let begin = info.systemUptime
// do something
let diff = (info.systemUptime - begin)
}
où diff:NSTimeInterval
est le temps écoulé en secondes.
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)
}
où diff:Double
est le temps écoulé en nanosecondes.
do {
let begin = clock()
// do something
let diff = Double(clock() - begin) / Double(CLOCKS_PER_SEC)
}
où diff:Double
est le temps écoulé en secondes.
Dans la documentation de CFAbsoluteTimeGetCurrent
:
Les appels répétés à cette fonction ne garantissent pas de façon monotone résultats croissants.
La raison est similaire à currentTimeMillis
vs nanoTime
en Java :
Vous ne pouvez pas utiliser l'un à l'autre fin. La raison en est que non l'horloge de l'ordinateur est parfaite; il dérive toujours et occasionnellement doit être corrigé. Cette correction peut soit arriver manuellement, ou dans le cas de la plupart des machines, il existe un processus qui 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, CFAbsoluteTime
fournit l'heure de l'horloge murale au lieu de l'heure de démarrage NSDate
est aussi l'heure de l'horloge murale.
let start = NSDate()
for index in 1...10000 {
// do nothing
}
let elapsed = start.timeIntervalSinceNow
// elapsed is a negative value.
Réponse rapide 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 varie bien sûr en fonction de la tâche, je vous montre simplement ceci pour que vous puissiez voir le niveau de précision décimale de cette mesure).
J'espère que cela aidera quelqu'un dans Swift 4 à partir de maintenant!
Vous pouvez créer une fonction time
pour mesurer vos appels . Je suis inspiré par Klaas ' answer.
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 description de la chaîne du temps écoulé.
Si vous ne souhaitez que le temps écoulé, vous pouvez le faire time (isPrime(7)).duration
Il suffit de copier et coller cette fonction. Écrit dans Swift 5. Copier 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
}
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
startTime
et endTime
sont du type TimeInterval
, qui est simplement un typealias
pour Double
, il est donc facile de le convertir en Int
ou autre Le temps est mesuré en secondes avec une précision inférieure à la milliseconde.DateInterval
, qui inclut une heure de début et de fin réelle.Fonction d'assistance 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")
}
Utilisation:
printExecutionTime(withTag: "Init") {
// Do your work here
}
Résultat: #Init - execution took 1.00104497105349 seconds
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. Mais les secondes ont beaucoup de décimales et semblent intercepter de petits changements de code dans des algorithmes comme QuickSort en utilisant swap () par rapport à swap urself etc.
Pensez à augmenter vos optimisations de construction lorsque vous testez les performances:
vous pouvez mesurer les nanosecondes comme par exemple. ce:
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)")
Enveloppez-le dans un bloc d'achèvement 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)")
}
J'ai emprunté l'idée de Klaas pour 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
Il n'est pas nécessaire d'appeler la fonction d'arrêt, 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 du code, utilisez timer.stop()
, il peut également être utilisé pour renvoyer le temps en secondes: let seconds = timer.stop()
Une fois le chronomètre arrêté, le minuteur d'intervalle ne sera pas, de sorte que print("Running: \(timer) ")
donnera la valeur 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"}
}
}
C’est l’extrait que j’ai conçu et qui semble fonctionner pour moi sur mon Macbook avec Swift 4.
Jamais testé sur d'autres systèmes, mais j'ai pensé qu'il valait la peine de le partager.
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 d'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")
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 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)")
Voici comment 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 il 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.")
Classe statique Swift3 pour la synchronisation des fonctions de base. Il gardera trace de chaque minuterie par nom. Appelez comme cela au moment où vous voulez commencer à mesurer:
Stopwatch.start(name: "PhotoCapture")
Appelez ceci pour capturer et imprimer le temps écoulé:
Stopwatch.timeElapsed(name: "PhotoCapture")
Voici la sortie: *** PhotoCapture écoulé ms: 1402.415125 Il existe un paramètre "useNanos" si vous souhaitez utiliser nanos . N'hésitez pas à le modifier si nécessaire.
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))")
}
}
}