Medir el tiempo transcurrido en Swift

132

¿Cómo podemos medir el tiempo transcurrido para ejecutar una función en Swift? Estoy tratando de mostrar el tiempo transcurrido de esta manera: "El tiempo transcurrido es 0,05 segundos". Vimos que en Java , podemos usar System.nanoTime (), ¿hay métodos equivalentes disponibles en Swift para lograr esto?

Por favor, eche un vistazo al programa de muestra:

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
fuente
1
no está relacionado con su problema de medición de tiempo, pero el ciclo se puede detener en sqrt(number)lugar de number, y puede ahorrar un poco más de tiempo, pero hay muchas más ideas que optimizan la búsqueda de números primos.
holex
@holex Por favor ignore el algoritmo utilizado. ¿Estoy tratando de descubrir cómo podemos medir el tiempo transcurrido?
Vaquita
1
puedes usar NSDateobjetos y puedes medir la diferencia entre ellos.
holex
44
Si está utilizando XCode, le recomiendo que use la nueva función de prueba de rendimiento. Hace todo el trabajo pesado por ti e incluso lo ejecuta varias veces y te da el tiempo promedio con su desviación estándar ...
Roshan
1
@dumbledad Puede medir el rendimiento de bloques completos directamente en pruebas unitarias. Por ejemplo, mira esto . Si desea desglosar aún más (por ejemplo, código de línea por línea), consulte Time Profiler, que forma parte de los instrumentos. Esto es mucho más poderoso y completo.
Roshan

Respuestas:

229

Aquí hay una función Swift que escribí para medir los problemas del Proyecto Euler en Swift

A partir de Swift 3, ahora hay una versión de Grand Central Dispatch que está "acelerada". Entonces, la respuesta correcta es probablemente usar la API DispatchTime .

Mi función se vería así:

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

Vieja respuesta

Para Swift 1 y 2, mi función usa 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
}

Tenga en cuenta que se desaconseja el uso de NSdate para las funciones de temporización: " La hora del sistema puede disminuir debido a la sincronización con referencias de hora externas o debido a un cambio explícito del reloj del usuario ".

JeremyP
fuente
Esto parece dar resultados buenos hasta alrededor de +/- 2microsec. Quizás eso varía según la plataforma, sin embargo.
user1021430
66
swift3 no funciona para mí, devuelve 0.0114653027, lo que sé por un hecho que no es cierto, el que tiene fechas devuelve 4.77720803022385seg
Cristi Băluță
55
Lamentablemente no. El tiempo de actividad está completamente agotado por alguna razón. Tengo una prueba que dice que tomó 1004959766 nanosegundos (aproximadamente un segundo), pero definitivamente se ejecutó durante aproximadamente 40 segundos. Lo utilicé al Datelado, y efectivamente eso reporta 41.87 segundos. No sé qué uptimeNanosecondsestá haciendo, pero no informa la duración correcta.
jowie
2
Perdón por la gran edición, priorizando su nueva solución, pero incluso recomendaría eliminar su código NSDate por completo: no es confiable usar NSDate: NSDate se basa en el reloj del sistema, que puede cambiar en cualquier momento debido a muchas razones diferentes, como como sincronización de hora de red (NTP) actualizando el reloj (a menudo se ajusta para la deriva), ajustes de DST, segundos intercalares y ajuste manual del reloj del usuario. Además, ya no puede publicar en AppStore ninguna aplicación que use Swift 1: Swift 3 es lo mínimo. Por lo tanto, no tiene sentido mantener su código NSDate más que decir "no lo haga".
Coeur
1
@ Cœur su crítica a la versión NSDate es válida (excepto que los cambios de DST no afectarán a NSDate, que siempre está en GMT), y su edición para revertir el orden definitivamente es una mejora.
JeremyP
69

Esta es una práctica clase de temporizador basada en 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
        }
    }
}

Puedes usarlo así:

let timer = ParkBenchTimer()

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

println("The task took \(timer.stop()) seconds.")
Klaas
fuente
44
" Las llamadas repetidas a esta función no garantizan resultados monotónicamente crecientes ", según su documentación .
Franklin Yu
8
Más contexto: "Las llamadas repetidas a esta función no garantizan resultados que aumenten monotónicamente. La hora del sistema puede disminuir debido a la sincronización con referencias de hora externas o debido a un cambio explícito del reloj del usuario ".
Klaas
El desarrollador debe tener en cuenta la "sincronización con referencias de tiempo externas" y "un cambio explícito del reloj del usuario". ¿Quiso decir que es imposible que ocurran las dos situaciones?
Franklin Yu
@FranklinYu no, solo quería decir que estas son las dos posibles razones. Si confía en obtener siempre valores monotónicamente crecientes, hay otras opciones.
Klaas
a veces deseo medir un corto período de tiempo; si la sincronización ocurre durante eso, puedo terminar con un tiempo negativo. En realidad, existe el mach_absolute_timeque no sufre este problema, por lo que me pregunto por qué ese no es ampliamente conocido. Quizás solo porque no está bien documentado.
Franklin Yu
54

Use clock, ProcessInfo.systemUptimeo DispatchTimepara un tiempo de inicio simple.


Hasta donde yo sé, hay al menos diez formas de medir el tiempo transcurrido:

Reloj monotónico basado:

  1. ProcessInfo.systemUptime.
  2. mach_absolute_timecon mach_timebase_infolo mencionado en esta respuesta .
  3. clock()en POSIX estándar .
  4. times()en POSIX estándar . (Demasiado complicado ya que necesitamos considerar el tiempo de usuario frente al tiempo del sistema, y ​​los procesos secundarios están involucrados).
  5. DispatchTime (un contenedor alrededor de Mach time API) como lo menciona JeremyP en la respuesta aceptada
  6. CACurrentMediaTime().

Reloj de pared basado:

(nunca los use para métricas: vea a continuación por qué)

  1. NSDate/ Datecomo lo mencionaron otros.
  2. CFAbsoluteTime según lo mencionado por otros.
  3. DispatchWallTime.
  4. gettimeofday()en POSIX estándar .

Las opciones 1, 2 y 3 se detallan a continuación.

Opción 1: API de información de proceso en Foundation

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

donde diff:NSTimeIntervales el tiempo transcurrido por segundos.

Opción 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)
}

donde diff:Doublees el tiempo transcurrido en nano-segundos.

Opción 3: API de reloj POSIX

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

donde diff:Doublees el tiempo transcurrido por segundos.

¿Por qué no la hora del reloj de pared para el tiempo transcurrido?

En la documentación de CFAbsoluteTimeGetCurrent:

Las llamadas repetidas a esta función no garantizan resultados monotónicamente crecientes.

La razón es similar a currentTimeMillisvs nanoTimeen Java :

No puedes usar el uno para el otro propósito. La razón es que el reloj de ninguna computadora es perfecto; siempre va a la deriva y ocasionalmente debe corregirse. Esta corrección puede ocurrir manualmente, o en el caso de la mayoría de las máquinas, hay un proceso que se ejecuta y continuamente emite pequeñas correcciones al reloj del sistema ("reloj de pared"). Estos tienden a suceder a menudo. Otra corrección de este tipo ocurre cada vez que hay un salto de segundo.

Aquí CFAbsoluteTimeproporciona la hora del reloj de pared en lugar de la hora de inicio. NSDatees la hora del reloj de pared también.

Franklin Yu
fuente
la mejor respuesta, ¿pero qué demonios es el mejor enfoque?
Fattie
1
La opción 5 se adapta mejor a mí. Si está considerando un código multiplataforma, pruebe este. Ambas bibliotecas Darwin y Glibc tienen clock()función.
Misha Svyatoshenko
Para las soluciones basadas en el reloj del sistema: tuve éxito con ProcessInfo.processInfo.systemUptime, mach_absolute_time(), DispatchTime.now()y CACurrentMediaTime(). Pero la solución con clock()no estaba convirtiendo a segundos correctamente. Así que yo le aconsejaría para actualizar su primera frase de: " Uso ProcessInfo.systemUptime o DispatchTime por el tiempo de puesta en marcha precisa. "
Coeur
36

La respuesta más rápida de Swift 4:

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

Le imprimirá algo así como 1.02107906341553 segundos transcurridos (el tiempo, por supuesto, variará dependiendo de la tarea, solo les estoy mostrando esto para que vean el nivel de precisión decimal para esta medición).

¡Espero que ayude a alguien en Swift 4 de ahora en adelante!

Actualizar

Si desea tener una forma genérica de probar porciones de código, le sugiero el siguiente fragmento:

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
fuente
¿Alguien puede explicar por qué * -1?
Maksim Kniazev
1
@MaksimKniazev Debido a que es un valor negativo, ¡la gente quiere uno positivo!
thachnb
@thachnb No tenía idea de que "beginPoint.timeIntervalSinceNow" produce un valor negativo ...
Maksim Kniazev
1
@MaksimKniazev Apple dice que: si el objeto de fecha es anterior a la fecha y hora actuales, el valor de esta propiedad es negativo.
Peter Guan
13
let start = NSDate()

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

let elapsed = start.timeIntervalSinceNow

// elapsed is a negative value.
usuario3370455
fuente
2
abs (start.timeIntervalSinceNow) // <- valor positivo
eonist
más o menos la solución más sencilla que he visto, gracias
MiladiuM
10

Simplemente copie y pegue esta función. Escrito en Swift 5. Copiando JeremyP aquí.

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

Úselo como

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

Puede crear una timefunción para medir sus llamadas. Me inspira la respuesta 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.")
}

Esta función le permitiría llamarlo así, time (isPrime(7))lo que devolvería una tupla que contiene el resultado y una descripción de cadena del tiempo transcurrido.

Si solo desea el tiempo transcurrido, puede hacerlo time (isPrime(7)).duration

Mellson
fuente
3
"Las llamadas repetidas a esta función no garantizan resultados monotónicamente crecientes". De acuerdo a la documentación .
Franklin Yu
3

Función auxiliar simple para medir el tiempo de ejecución con cierre.

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
}

Resultado: #Init - execution took 1.00104497105349 seconds

Vadim Akhmerov
fuente
2

puede medir los nanosegundos de la siguiente manera:

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
fuente
Acabo de ejecutar esto sin código colocado en "// su procedimiento largo", y dio un resultado de 240900993, que es 0.24 segundos.
user1021430
crear instancias de un NSCalendarprocedimiento costoso, pero puede hacerlo antes de comenzar a ejecutar su procedimiento, por lo que no se agregará al tiempo de ejecución de su procedimiento largo ... tenga en cuenta que la creación de una NSDateinstancia y el –components(_:, fromDate:)método de llamada aún requieren tiempo, por lo que probablemente nunca obtendrás 0.0nanosegundos.
holex
Desde el aspecto del constructor NSCalendar, parece que no es posible crearlo antes de tiempo (startDate es una entrada requerida). Es sorprendente que parezca un cerdo.
user1021430
puede hacer esto (mi respuesta actualizada), el tiempo medido sin ningún procedimiento adicional es de aproximadamente 6.9microsegundos en mi dispositivo.
holex
Genial, gracias. El procedimiento básico ahora es similar a la respuesta de JeremyP, pero el informe es diferente.
user1021430
2

Yo uso esto:

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

No sé si es más o menos preciso que el publicado anteriormente. Pero los segundos tienen muchos decimales y parecen captar pequeños cambios de código en algoritmos como QuickSort usando swap () versus implementar swap urself, etc.

Recuerde aumentar sus optimizaciones de compilación cuando pruebe el rendimiento:

Optimizaciones rápidas del compilador

Peheje
fuente
2

Aquí está mi intento por la respuesta más 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

Notas

  • startTimey endTimeson del tipo TimeInterval, que es solo typealiaspara Double, por lo que es fácil convertirlo a uno Into lo que sea. El tiempo se mide en segundos con una precisión inferior a milisegundos.
  • Consulte también DateInterval, que incluye una hora de inicio y finalización real.
  • Usar el tiempo desde 1970 es similar a las marcas de tiempo de Java .
Suragch
fuente
la manera más fácil, me gustaría en dos cadenas, la segunda se deja transcurrirTime = Date (). timeIntervalSince1970 - startTime
FreeGor
1

He tomado prestada la idea de Klaas para crear una estructura ligera para medir el tiempo de ejecución y el intervalo:

Uso del código:

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

No es necesario llamar a la función de parada, ya que la función de impresión dará el tiempo transcurrido. Se puede llamar repetidamente para que transcurra el tiempo. Pero para detener el temporizador en cierto punto del uso del código timer.stop(), también puede usarse para devolver el tiempo en segundos: let seconds = timer.stop() después de que se detiene el temporizador, el temporizador de intervalo no lo print("Running: \(timer) ")hará , por lo que dará la hora correcta incluso después de unas pocas líneas de código.

El siguiente es el código para RunningTimer. Está probado para 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
fuente
1

Envuélvala en un bloque de terminación para facilitar su uso.

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

Este es el fragmento que se me ocurrió y parece funcionar para mí en mi Macbook con Swift 4.

Nunca probé en otros sistemas, pero pensé que vale la pena compartir de todos modos.

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

Aquí hay un ejemplo de cómo usarlo:

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

Otra forma es hacerlo más explícitamente:

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
fuente
0

Así es como lo escribí.

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

Para medir un algoritmo utilízalo así.

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

print("Block is running \(time) seconds.")
BilalReffas
fuente
¿Qué tan exacto es ese momento? Porque usé el temporizador antes para actualizar cada 0.1 segundos. Comparé esta respuesta y una con el temporizador y el resultado de esta respuesta es 0.1 segundos es más que con el temporizador ..
Maksim Kniazev
0

Clase Swift3 estática para temporización de funciones básicas. Realizará un seguimiento de cada temporizador por nombre. Llámelo así en el punto en que desea comenzar a medir:

Stopwatch.start(name: "PhotoCapture")

Llame a esto para capturar e imprimir el tiempo transcurrido:

Stopwatch.timeElapsed(name: "PhotoCapture")

Este es el resultado: *** PhotoCapture transcurrió ms: 1402.415125 Hay un parámetro "useNanos" si desea usar nanos. Por favor, siéntase libre de cambiar según sea necesario.

   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
fuente
Todo su trabajo mach_timebase_infoya está implementado mejor de lo que lo hizo en el código fuente de ProcessInfo.processInfo.systemUptime. Así que simplemente hazlo watches[name] = ProcessInfo.processInfo.systemUptime. Y * TimeInterval(NSEC_PER_MSEC)si quieres nanos.
Coeur
0

Basado en la respuesta de Franklin Yu y los comentarios de Coeur

Detalles

  • Xcode 10.1 (10B61)
  • Swift 4.2

Solución 1

medida(_:)

Solución 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)
    }
}

Uso de la solución 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
fuente
No estoy seguro de por qué necesitaríamos usar implementaciones variables. Usar Datepara medir cualquier cosa es extremadamente desaconsejado (pero systemUptimeo clock()está bien). En cuanto a las pruebas, ya lo hemos measure(_:)hecho.
Coeur
1
Otra nota: ¿por qué hacer el cierre opcional?
Coeur
@ Cœur tienes razón! Gracias por tus comentarios. Actualizaré la publicación más tarde.
Vasily Bodnarchuk