Ukur waktu yang berlalu dalam Swift

132

Bagaimana kita bisa mengukur waktu yang telah berlalu untuk menjalankan fungsi di Swift? Saya mencoba untuk menampilkan waktu yang telah berlalu seperti ini: "Waktu yang berlalu adalah .05 detik". Melihat bahwa di Jawa , kita dapat menggunakan System.nanoTime (), apakah ada metode setara yang tersedia di Swift untuk mencapai ini?

Silakan lihat contoh programnya:

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
sumber
1
itu tidak terkait dengan masalah pengukur waktu Anda, tetapi loop dapat berhenti di sqrt(number)bukan number, dan Anda dapat menyimpan waktu yang lebih sedikit - tetapi ada banyak lagi ide-ide mengoptimalkan mencari bilangan prima.
holex
@holex Abaikan algoritma yang digunakan. Saya mencoba mencari tahu bagaimana kita bisa mengukur waktu yang telah berlalu?
Vaquita
1
Anda dapat menggunakan NSDateobjek dan Anda dapat mengukur perbedaan di antara mereka.
holex
4
Jika Anda menggunakan XCode, saya sarankan Anda menggunakan fitur pengujian kinerja baru. Ia melakukan semua pekerjaan berat untuk Anda dan bahkan menjalankannya berkali-kali dan memberi Anda waktu rata-rata dengan deviasi standarnya ...
Roshan
1
@dumbledad Anda dapat mengukur kinerja seluruh blok secara langsung dalam pengujian unit. Sebagai contoh, lihat ini . Jika Anda ingin memecah run down lebih jauh (misalnya, kode baris demi baris), periksa Time Profiler yang merupakan bagian dari Instrumen. Ini jauh lebih kuat dan komprehensif.
Roshan

Jawaban:

229

Inilah fungsi Swift yang saya tulis untuk mengukur masalah Project Euler di Swift

Pada Swift 3, sekarang ada versi Grand Central Dispatch yang "swiftified". Jadi jawaban yang benar mungkin menggunakan API DispatchTime .

Fungsi saya akan terlihat seperti:

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

Jawaban lama

Untuk Swift 1 dan 2, fungsi saya menggunakan 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
}

Perhatikan bahwa menggunakan NSdate untuk fungsi pengaturan waktu tidak disarankan: " Waktu sistem dapat menurun karena sinkronisasi dengan referensi waktu eksternal atau karena perubahan pengguna yang eksplisit dari jam. ".

JeremyP
sumber
Ini tampaknya memberikan hasil yang baik hingga sekitar +/- 2microsec. Mungkin itu bervariasi berdasarkan platform.
user1021430
6
swift3 tidak bekerja untuk saya, itu mengembalikan 0,0114653027 yang saya tahu untuk fakta yang tidak benar, yang dengan tanggal mengembalikan 4.77720803022385sec
Cristi Băluță
5
Sayangnya tidak. Waktu habis sepenuhnya karena beberapa alasan. Saya memiliki tes yang mengatakan butuh 1004959766 nanodetik (sekitar satu detik), tetapi pasti berjalan sekitar 40 detik. Saya menggunakan di Datesamping, dan tentu saja itu melaporkan 41,87 detik. Saya tidak tahu apa uptimeNanosecondsyang dilakukan, tetapi tidak melaporkan durasi yang benar.
jowie
2
Maaf untuk hasil edit besar, memprioritaskan solusi baru Anda, tetapi saya bahkan akan merekomendasikan untuk menghapus kode NSDate Anda sepenuhnya: itu sama sekali tidak dapat diandalkan untuk menggunakan NSDate: NSDate didasarkan pada jam sistem, yang dapat berubah setiap saat karena berbagai alasan, seperti sebagai sinkronisasi waktu jaringan (NTP) memperbarui jam (sering terjadi untuk menyesuaikan drift), penyesuaian DST, detik kabisat, dan penyesuaian jam secara manual. Selain itu, Anda tidak dapat mempublikasikan lagi di AppStore aplikasi apa pun menggunakan Swift 1: Swift 3 adalah minimum. Jadi tidak ada gunanya menyimpan kode NSDate Anda selain mengatakan "jangan lakukan itu".
Cœur
1
@Cœur kritik Anda terhadap versi NSDate valid (kecuali perubahan DST tidak akan mempengaruhi NSDate yang selalu dalam GMT), dan hasil edit Anda untuk membalik urutan pasti merupakan peningkatan.
JeremyP
69

Ini adalah kelas Timer berguna berdasarkan 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
        }
    }
}

Anda bisa menggunakannya seperti ini:

let timer = ParkBenchTimer()

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

println("The task took \(timer.stop()) seconds.")
Klaas
sumber
4
" Panggilan berulang ke fungsi ini tidak menjamin hasil yang meningkat secara monoton, " menurut dokumentasinya .
Franklin Yu
8
Lebih banyak konteks: "Panggilan berulang ke fungsi ini tidak menjamin hasil yang meningkat secara monoton. Waktu sistem dapat berkurang karena sinkronisasi dengan referensi waktu eksternal atau karena perubahan jam yang dilakukan oleh pengguna secara eksplisit ."
Klaas
Pengembang harus mempertimbangkan "sinkronisasi dengan referensi waktu eksternal" dan "perubahan jam pengguna secara eksplisit". Apakah maksud Anda bahwa tidak mungkin kedua situasi itu terjadi?
Franklin Yu
@ FranklinYu tidak, saya hanya ingin menyatakan ini adalah dua alasan yang mungkin. Jika Anda mengandalkan selalu mendapatkan nilai yang meningkat secara monoton ada opsi lain.
Klaas
terkadang saya ingin mengukur periode waktu yang singkat; jika sinkronisasi terjadi selama itu, saya mungkin berakhir dengan waktu negatif. Sebenarnya ada mach_absolute_timeyang tidak menderita dari masalah ini, jadi saya bertanya-tanya mengapa itu tidak diketahui secara luas. Mungkin hanya karena tidak terdokumentasi dengan baik.
Franklin Yu
54

Gunakan clock,, ProcessInfo.systemUptimeatau DispatchTimeuntuk waktu mulai yang sederhana.


Sejauh yang saya tahu, setidaknya ada sepuluh cara untuk mengukur waktu yang telah berlalu:

Berbasis Jam Monoton:

  1. ProcessInfo.systemUptime.
  2. mach_absolute_timedengan mach_timebase_infosebagaimana disebutkan dalam jawaban ini .
  3. clock()dalam standar POSIX .
  4. times()dalam standar POSIX . (Terlalu rumit karena kita perlu mempertimbangkan waktu pengguna vs waktu sistem, dan proses anak terlibat.)
  5. DispatchTime (pembungkus sekitar API waktu Mach) sebagaimana disebutkan oleh JeremyP dalam jawaban yang diterima.
  6. CACurrentMediaTime().

Berbasis Jam Dinding:

(jangan pernah gunakan itu untuk metrik: lihat alasannya di bawah)

  1. NSDate/ DateSeperti yang disebutkan oleh orang lain.
  2. CFAbsoluteTime seperti yang disebutkan oleh orang lain.
  3. DispatchWallTime.
  4. gettimeofday()dalam standar POSIX .

Opsi 1, 2 dan 3 diuraikan di bawah ini.

Opsi 1: API Info Proses dalam Yayasan

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

di mana diff:NSTimeIntervalwaktu yang berlalu oleh detik.

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

di mana diff:Doublewaktu yang berlalu oleh nano-detik.

Opsi 3: API jam POSIX

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

di mana diff:Doublewaktu yang berlalu oleh detik.

Mengapa Bukan Jam Dinding untuk Masa Berlalu?

Dalam dokumentasi CFAbsoluteTimeGetCurrent:

Panggilan berulang ke fungsi ini tidak menjamin hasil yang meningkat secara monoton.

Alasannya mirip dengan currentTimeMillisvs nanoTimedi Jawa :

Anda tidak dapat menggunakan yang satu untuk tujuan yang lain. Alasannya adalah tidak ada jam komputer yang sempurna; selalu melayang dan kadang-kadang perlu diperbaiki. Koreksi ini dapat terjadi secara manual, atau dalam kasus kebanyakan mesin, ada proses yang berjalan dan terus-menerus mengeluarkan koreksi kecil pada jam sistem ("jam dinding"). Ini cenderung sering terjadi. Koreksi lain seperti itu terjadi setiap kali ada lompatan kedua.

Di sini CFAbsoluteTimemenyediakan waktu jam dinding alih-alih waktu memulai. NSDateadalah waktu jam dinding juga.

Franklin Yu
sumber
jawaban terbaik - tapi apa, sih, pendekatan terbaik untuk diambil ?!
Fattie
1
Opsi 5 paling cocok untuk saya. Jika Anda mempertimbangkan kode multi-platform, coba yang ini. Baik perpustakaan Darwin maupun Glibc memiliki clock()fungsi.
Misha Svyatoshenko
Untuk solusi berbasis Sistem Jam: Aku telah sukses dengan ProcessInfo.processInfo.systemUptime, mach_absolute_time(), DispatchTime.now()dan CACurrentMediaTime(). Tetapi solusi dengan clock()itu tidak mengkonversi ke detik dengan benar. Jadi saya akan menyarankan untuk memperbarui kalimat pertama Anda ke: " Gunakan ProcessInfo.systemUptime atau DispatchTime untuk waktu start-up yang akurat. "
Cœur
36

Swift 4 jawaban terpendek:

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

Ini akan mencetak Anda sesuatu seperti 1,02107906341553 detik berlalu (waktu tentu akan bervariasi tergantung pada tugas, saya hanya menunjukkan ini untuk kalian untuk melihat tingkat presisi desimal untuk pengukuran ini).

Semoga ini bisa membantu seseorang di Swift 4 mulai sekarang!

Memperbarui

Jika Anda ingin memiliki cara umum untuk menguji bagian-bagian kode, saya akan menyarankan potongan berikutnya:

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
sumber
Adakah yang bisa menjelaskan mengapa * -1?
Maksim Kniazev
1
@MaksimKniazev Karena ini bernilai negatif, orang ingin yang positif!
thachnb
@ thachnb Saya tidak tahu "startingPoint.timeIntervalSinceNow" menghasilkan nilai negatif ...
Maksim Kniazev
1
@MaksimKniazev Apple mengatakan bahwa: Jika objek tanggal lebih awal dari tanggal dan waktu saat ini, nilai properti ini negatif.
Peter Guan
13
let start = NSDate()

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

let elapsed = start.timeIntervalSinceNow

// elapsed is a negative value.
pengguna3370455
sumber
2
abs (start.timeIntervalSinceNow) // // - nilai positif
eonist
cukup banyak solusi ke depan yang paling lurus yang pernah saya lihat, terima kasih
MiladiuM
10

Cukup Salin dan Tempel fungsi ini. Ditulis dengan cepat 5. Menyalin JeremyP di sini.

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

Gunakan seperti

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

Anda dapat membuat timefungsi untuk mengukur panggilan Anda. Saya terinspirasi oleh jawaban 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.")
}

Fungsi ini akan memungkinkan Anda untuk memanggilnya seperti ini time (isPrime(7))yang akan mengembalikan tuple yang berisi hasil dan deskripsi string dari waktu yang telah berlalu.

Jika Anda hanya ingin waktu yang telah berlalu, Anda dapat melakukan ini time (isPrime(7)).duration

Mellson
sumber
3
"Panggilan berulang ke fungsi ini tidak menjamin hasil yang meningkat secara monoton." menurut dokumentasi .
Franklin Yu
3

Fungsi pembantu sederhana untuk mengukur waktu eksekusi dengan penutupan.

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

Pemakaian:

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

Hasil: #Init - execution took 1.00104497105349 seconds

Vadim Akhmerov
sumber
2

Anda dapat mengukur nanodetik seperti misalnya ini:

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
sumber
Saya hanya menjalankan ini tanpa kode yang ditempatkan di "// prosedur panjang Anda", dan itu memberikan hasil 240900993, yaitu 0,24 detik.
user1021430
instantiating NSCalendarprosedur yang mahal, tetapi Anda bisa melakukannya sebelum Anda mulai menjalankan prosedur Anda, jadi prosedur itu tidak akan ditambahkan ke runtime prosedur panjang Anda ... ingat memanggil pembuatan membuat NSDateinstance dan –components(_:, fromDate:)metode panggilan masih membutuhkan waktu, jadi mungkin Anda tidak akan pernah mendapatkan 0.0nanodetik.
holex
Dari tampilan konstruktor NSCalendar, tampaknya tidak mungkin untuk membuatnya sebelumnya (startDate adalah input yang diperlukan). Agak mengherankan bahwa tampaknya seperti babi.
user1021430
Anda dapat melakukan ini (jawaban saya yang diperbarui), waktu yang diukur tanpa prosedur tambahan adalah tentang 6.9mikrodetik pada perangkat saya.
holex
Keren Terimakasih. Prosedur dasar sekarang mirip dengan jawaban JeremyP, tetapi pelaporannya berbeda.
user1021430
2

Saya menggunakan ini:

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

Saya tidak tahu apakah ini lebih atau kurang akurat daripada yang diposting sebelumnya. Tetapi detik memiliki banyak desimal dan tampaknya menangkap perubahan kode kecil dalam algoritma seperti QuickSort menggunakan swap () vs. menerapkan swap sendiri dll.

Ingat untuk meningkatkan optimisasi bangunan Anda saat menguji kinerja:

Optimalisasi kompiler Swift

Peheje
sumber
2

Inilah upaya saya untuk jawaban yang paling sederhana:

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

Catatan

  • startTimedan endTimedari jenisnya TimeInterval, yang hanya typealiasuntuk Double, jadi mudah untuk mengubahnya menjadi Intatau apa pun. Waktu diukur dalam detik dengan presisi sub-milidetik.
  • Lihat juga DateInterval, yang mencakup waktu mulai dan berakhir yang sebenarnya.
  • Menggunakan waktu sejak tahun 1970 mirip dengan cap waktu Java .
Suragch
sumber
cara termudah, akan suka dalam dua string, yang kedua adalah membiarkan elapsedTime = Date (). timeIntervalSince1970 - startTime
FreeGor
1

Saya telah meminjam ide dari Klaas untuk membuat struct ringan untuk mengukur berlari dan interval waktu:

Penggunaan Kode:

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

Fungsi berhenti tidak harus dipanggil, karena fungsi cetak akan memberikan waktu yang telah lewat. Ini dapat dipanggil berulang kali untuk mendapatkan waktu berlalu. Tetapi untuk menghentikan timer pada titik tertentu dalam penggunaan kode timer.stop()itu juga dapat digunakan untuk mengembalikan waktu dalam hitungan detik: let seconds = timer.stop() Setelah timer dihentikan, timer interval tidak akan, sehingga print("Running: \(timer) ")akan memberikan waktu yang benar bahkan setelah beberapa baris kode.

Berikut ini adalah kode untuk RunningTimer. Ini diuji untuk 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
sumber
1

Bungkus di blok penyelesaian agar mudah digunakan.

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

Ini adalah cuplikan yang saya buat dan sepertinya bekerja untuk saya di Macbook saya dengan Swift 4.

Tidak pernah diuji pada sistem lain, tapi saya pikir tetap layak untuk dibagikan.

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

Berikut ini contoh cara menggunakannya:

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

Cara lain adalah melakukannya secara lebih eksplisit:

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

Ini adalah bagaimana saya menulisnya.

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

Untuk mengukur suatu algoritma, gunakan seperti itu.

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

print("Block is running \(time) seconds.")
BilalReffas
sumber
Seberapa akurat waktu itu? Karena saya menggunakan timer sebelumnya untuk memperbarui setiap 0,1 detik. Saya membandingkan jawaban ini dan satu dengan timer dan hasil dari jawaban ini adalah 0,1 detik lebih dari pada timer ..
Maksim Kniazev
0

Kelas Swift3 statis untuk pengaturan fungsi dasar. Ini akan melacak setiap timer dengan nama. Sebut saja seperti ini di titik yang ingin Anda ukur:

Stopwatch.start(name: "PhotoCapture")

Sebut ini untuk menangkap dan mencetak waktu yang telah berlalu:

Stopwatch.timeElapsed(name: "PhotoCapture")

Ini adalah output: *** PhotoCapture berlalu ms: 1402.415125 Ada parameter "useNanos" jika Anda ingin menggunakan nanos. Silakan berubah sesuai kebutuhan.

   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
sumber
Seluruh pekerjaan Anda dengan mach_timebase_infosudah dilaksanakan lebih baik daripada yang Anda lakukan dalam kode sumber dari ProcessInfo.processInfo.systemUptime. Jadi lakukan saja watches[name] = ProcessInfo.processInfo.systemUptime. Dan * TimeInterval(NSEC_PER_MSEC)jika Anda ingin nano.
Cœur
0

Berdasarkan jawaban Franklin Yu dan komentar Cœur

Detail

  • Xcode 10.1 (10B61)
  • Cepat 4.2

Solusi 1

mengukur(_:)

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

Penggunaan solusi 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)")
Bodnarchuk dengan mudah
sumber
Tidak yakin mengapa kita perlu menggunakan implementasi variabel. Menggunakan Dateuntuk mengukur apa pun sangat tidak dianjurkan (tapi systemUptimeatau clock()tidak apa-apa). Adapun tes, kami measure(_:)sudah.
Cœur
1
Catatan lain: mengapa membuat penutupan menjadi opsional?
Cœur
@Cur benar! Terima kasih atas komentar anda Saya akan memperbarui pos nanti.
Vasily Bodnarchuk