Swift ile geçen zamanı ölçün


132

Swift'de bir işlevi çalıştırmak için geçen süreyi nasıl ölçebiliriz? Geçen süreyi şu şekilde görüntülemeye çalışıyorum: "Geçen süre .05 saniye". Java'da System.nanoTime () kullanabileceğimizi gördüm , bunu başarmak için Swift'de eşdeğer yöntemler var mı?

Lütfen örnek programa bir göz atın:

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
bu sizin zaman ölçme sorununuzla ilgisizdir, ancak döngü sqrt(number)yerine durdurulabilir numberve biraz daha fazla zaman kazanabilirsiniz - ancak asal aramaları optimize eden çok daha fazla fikir vardır.
holex

@holex Lütfen kullanılan algoritmayı dikkate almayın. Geçen zamanı nasıl ölçebileceğimizi anlamaya çalışıyorum?
Vaquita

1
NSDatenesneleri kullanabilir ve aralarındaki farkı ölçebilirsiniz.
holex

4
XCode kullanıyorsanız, yeni performans testi özelliğini kullanmanızı tavsiye ederim. Tüm ağır işleri sizin için yapar ve hatta birkaç kez çalıştırır ve standart sapmasıyla size ortalama süre verir ...
Roshan

1
@dumbledad Tüm blokların performansını doğrudan birim testlerinde ölçebilirsiniz. Örneğin, buna bakın . Bir koşuyu daha da bölmek istiyorsanız (örneğin, satır kod), Aletlerin bir parçası olan Zaman Profilcisi'ne bakın . Bu çok daha güçlü ve kapsamlıdır.
Roshan

Yanıtlar:


229

İşte Swift'deki Project Euler sorunlarını ölçmek için yazdığım bir Swift işlevi

Swift 3'ten itibaren artık Grand Central Dispatch'in "hızlı" bir sürümü var. Dolayısıyla doğru cevap muhtemelen DispatchTime API'sini kullanmaktır .

İşlevim şuna benzer:

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

Eski cevap

Swift 1 ve 2 için işlevim NSDate'i kullanıyor:

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

Zamanlama işlevleri için NSdate'i kullanmanın tavsiye edilmediğini unutmayın: " Sistem zamanı, harici zaman referanslarıyla senkronizasyon nedeniyle veya saatin açık bir kullanıcı değişikliği nedeniyle azalabilir. "


Bu yaklaşık +/- 2 mikrosaniye kadar iyi sonuçlar veriyor gibi görünüyor. Ancak bu, platforma göre değişir.
user1021430

6
swift3 benim için çalışmıyor, doğru olmadığını bildiğim 0.0114653027'yi döndürüyor, tarihleri ​​olan 4.77720803022385sn
Cristi Băluță

5
Ne yazık ki değil. Çalışma süresi bazı nedenlerden dolayı tamamen tükendi. 1004959766 nanosaniye (yaklaşık bir saniye) sürdüğünü, ancak kesinlikle yaklaşık 40 saniye sürdüğünü söyleyen bir testim var. DateYanında kullandım ve 41.87 saniye bildiren yeterli. Ne yaptığını bilmiyorum uptimeNanosecondsama doğru süreyi bildirmiyor.
jowie

2
Büyük düzenleme için özür dilerim, yeni çözümünüze öncelik verirsiniz, ancak NSDate kodunuzu tamamen silmenizi bile tavsiye ederim: NSDate'i kullanmak tamamen güvenilmezdir: NSDate, birçok farklı nedenden dolayı herhangi bir zamanda değişebilir, bu gibi ağ zaman senkronizasyonu (NTP) olarak saati günceller (genellikle sapmayı ayarlamak için olur), DST ayarları, artık saniyeler ve saatin kullanıcı manuel ayarı. Ek olarak, Swift 1'i kullanan herhangi bir uygulamayı AppStore'da yayınlayamazsınız: Swift 3 minimumdur. Yani NSDate kodunuzu "bunu yapma" demekten başka saklamanın bir anlamı yoktur.
Cœur

1
@ NSDate sürümüne yönelik eleştiriniz geçerlidir (DST değişiklikleri, her zaman GMT'de olan NSDate'i etkilemez) ve sıralamayı tersine çevirmek için düzenlemeniz kesinlikle bir gelişmedir.
JeremyP

69

Bu dayanan kullanışlı bir zamanlayıcı sınıftır 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
        }
    }
}

Bunu şu şekilde kullanabilirsiniz:

let timer = ParkBenchTimer()

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

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

4
" Bu işleve Tekrarlanan aramalar sonucu monoton artan garanti etmez. " Onun göre belgeler .
Franklin Yu

8
Daha fazla bağlam: "Bu işleve tekrarlanan çağrılar, monoton olarak artan sonuçları garanti etmez. Sistem zamanı, harici zaman referansları ile senkronizasyon nedeniyle veya saatin açık bir kullanıcı değişikliği nedeniyle azalabilir ."
Klaas

Geliştirici, "harici zaman referanslarıyla senkronizasyon" ve "saatin açık bir kullanıcı değişikliğini" hesaba katmalıdır. İki durumun gerçekleşmesinin imkansız olduğunu mu söylediniz?
Franklin Yu

@FranklinYu hayır, sadece bunların iki olası neden olduğunu belirtmek istedim. Her zaman monoton olarak artan değerler almaya güveniyorsanız, başka seçenekler de vardır.
Klaas

bazen kısa bir süreyi ölçmek isterim; bu sırada senkronizasyon olursa, negatif zamanla karşılaşabilirim. Aslında mach_absolute_timebu sorundan muzdarip olmayan var, bu yüzden neden yaygın olarak bilinmediğini merak ediyorum. Belki de iyi belgelenmediği için.
Franklin Yu

54

Kullanım clock, ProcessInfo.systemUptimeya DispatchTimebasit başlangıç kez.


Bildiğim kadarıyla geçen zamanı ölçmenin en az on yolu var:

Monotonik Saat tabanlı:

  1. ProcessInfo.systemUptime.
  2. mach_absolute_timeile mach_timebase_infobelirtildiği gibi bu cevap .
  3. clock()içinde POSIX standardı .
  4. times()içinde POSIX standardı . (Kullanıcı zamanı ile sistem zamanını dikkate almamız gerektiğinden çok karmaşık ve alt süreçler de dahil.)
  5. DispatchTime (Mach zamanı API'si etrafında bir sarmalayıcı) JeremyP tarafından kabul edilen yanıtta belirtildiği gibi.
  6. CACurrentMediaTime().

Duvar Saati tabanlı:

(bunları asla ölçümler için kullanmayın: aşağıya bakın)

  1. NSDate/ Datebaşkaları tarafından belirtildiği gibi.
  2. CFAbsoluteTime diğerleri tarafından belirtildiği gibi.
  3. DispatchWallTime.
  4. gettimeofday()içinde POSIX standardı .

Seçenek 1, 2 ve 3 aşağıda detaylandırılmıştır.

Seçenek 1: Foundation'da Process Info API'si

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

diff:NSTimeIntervalsaniye cinsinden geçen zaman nerede .

Seçenek 2: Mach C API'si

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:Doublenano saniyelik geçen zaman nerede .

Seçenek 3: POSIX saat API'si

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

diff:Doublesaniye cinsinden geçen zaman nerede .

Geçen Zaman İçin Neden Duvar Saati Zamanı Değil?

Belgelerde CFAbsoluteTimeGetCurrent:

Bu işleve tekrarlanan çağrılar, tekdüze olarak artan sonuçları garanti etmez.

Nedeni benzer currentTimeMillisvs nanoTimeJava :

Birini diğer amaç için kullanamazsınız. Bunun nedeni, hiçbir bilgisayarın saatinin mükemmel olmamasıdır; her zaman sürüklenir ve bazen düzeltilmesi gerekir. Bu düzeltme manuel olarak gerçekleşebilir veya çoğu makinede, sistem saatinde sürekli olarak küçük düzeltmeler yapan ("duvar saati") bir süreç vardır. Bunlar sıklıkla olma eğilimindedir. Böyle bir başka düzeltme, artık bir saniye olduğunda gerçekleşir.

Burada CFAbsoluteTime, başlangıç ​​zamanı yerine duvar saati süresi sağlar. NSDateaynı zamanda duvar saati zamanıdır.


en iyi cevap - ama ne, lanet olsun, izlenecek en iyi yaklaşım nedir ?!
Fattie

1
5. Seçenek benim için en uygun olanı. Çoklu platform kodunu düşünüyorsanız, bunu deneyin. Hem Darwin hem de Glibc kütüphanelerinin clock()işlevi vardır.
Misha Svyatoshenko

Sistem Saat tabanlı çözümler için: Ben başarılı olmuş ProcessInfo.processInfo.systemUptime, mach_absolute_time(), DispatchTime.now()ve CACurrentMediaTime(). Ancak çözüm, clock()saniyelere gerektiği gibi dönüştürülmüyordu. Bu nedenle, ilk cümlenizi şu şekilde güncellemenizi tavsiye ederim: " Doğru başlangıç ​​zamanı için ProcessInfo.systemUptime veya DispatchTime kullanın. "
Cœur

36

Swift 4 en kısa cevap:

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

Size geçen 1.02107906341553 saniye gibi bir şey basacaktır (süre, göreve göre değişecektir, bu ölçüm için ondalık hassasiyet seviyesini görmeniz için size bunu gösteriyorum).

Umarım bundan sonra Swift 4'teki birine yardımcı olur!

Güncelleme

Kod bölümlerini test etmenin genel bir yoluna sahip olmak istiyorsanız, sonraki parçacığı öneririm:

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

Birisi neden * -1'i açıklayabilir mi?
Maksim Kniazev

1
@MaksimKniazev Negatif bir değer olduğu için insanlar pozitif bir değer ister!
thachnb

@thachnb "beginPoint.timeIntervalSinceNow" negatif değer üretiyor ...
Maksim Kniazev

1
@MaksimKniazev Apple şunu söylüyor: Tarih nesnesi geçerli tarih ve saatten önceyse, bu özelliğin değeri negatiftir.
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) // <- pozitif değer
eonist

hemen hemen gördüğüm en basit çözüm, teşekkür ederim
MiladiuM

10

Sadece bu işlevi Kopyala ve Yapıştır. Hızlı bir şekilde yazıldı. 5. JeremyP burada kopyalanıyor.

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

Gibi kullan

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

6

timeÇağrılarınızı ölçmek için bir işlev oluşturabilirsiniz . Klaas'ın cevabından ilham aldım .

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

Bu işlev time (isPrime(7)), sonucu içeren bir tuple ve geçen zamanın bir dize tanımını döndürecek şekilde onu bu şekilde çağırmanıza izin verir .

Sadece geçen zamanı diliyorsan bunu yapabilirsin time (isPrime(7)).duration


3
"Bu işleve tekrarlanan çağrılar, tekdüze artan sonuçları garanti etmez." belgelere göre .
Franklin Yu

3

Kapanma ile yürütme süresini ölçmek için basit yardımcı fonksiyon.

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

Kullanımı:

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

Sonuç: #Init - execution took 1.00104497105349 seconds


2

nanosaniyeleri şu şekilde ölçebilirsiniz :

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

Bunu "// uzun prosedürünüze" kod yerleştirmeden çalıştırdım ve 0.24 saniye olan 240900993 sonucunu verdi.
user1021430

Bir NSCalendaryordamı örneklemek pahalı bir yordamdır, ancak yordamı çalıştırmaya başlamadan önce yapabilirsiniz , bu nedenle uzun yordamınızın çalışma süresine eklenmez ... bir NSDateörnek oluşturmanın ve çağırma –components(_:, fromDate:)yönteminin hala zaman alacağını unutmayın asla 0.0nanosaniye alamayacaksınız .
holex

NSCalendar kurucusunun görünümünden, onu önceden oluşturmak mümkün olmayabilir (startDate gerekli bir giriştir). Böyle bir domuz gibi görünmesi biraz şaşırtıcı.
user1021430

bunu yapabilirsiniz (güncellenmiş cevabım), herhangi bir ek prosedür olmaksızın ölçülen süre 6.9cihazımdaki mikrosaniyedir.
holex

Harika, teşekkürler. Temel prosedür artık JeremyP'nin cevabına benzer, ancak raporlama farklıdır.
user1021430

2

Bunu kullanıyorum:

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

Daha önce gönderilenden daha fazla veya daha az doğru olup olmadığını bilmiyorum. Ancak saniyeler çok sayıda ondalık sayıya sahiptir ve swap () kullanarak QuickSort gibi algoritmalarda küçük kod değişikliklerini yakalıyor gibi görünmektedir.

Performansı test ederken derleme optimizasyonlarınızı artırmayı unutmayın:

Swift derleyici optimizasyonları


2

İşte en basit cevap için denemem:

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

notlar

  • startTimeve endTimetiptedir TimeIntervaladil olduğunu typealiasiçin Doublebir dönüştürmek kolaydır böylece, Intya da her neyse. Zaman, milisaniyenin altında bir hassasiyetle saniye cinsinden ölçülür.
  • Ayrıca DateInterval, gerçek bir başlangıç ​​ve bitiş saati içeren bkz .
  • 1970'ten beri kullanılan zamanı kullanmak Java zaman damgalarına benzer .

en kolay yol, iki dizede
FreeGor

1

Koşu ve aralık süresini ölçmek için hafif bir yapı oluşturma fikrini Klaas'tan ödünç aldım:

Kod Kullanımı:

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

Yazdırma işlevi geçen süreyi vereceğinden, durdurma işlevinin çağrılmasına gerek yoktur. Geçen süreyi almak için tekrar tekrar çağrılabilir. Ancak, zamanlayıcıyı kodun belirli bir noktasında durdurmak için timer.stop(), zamanı saniye cinsinden döndürmek için de kullanılabilir: let seconds = timer.stop() Zamanlayıcı durdurulduktan sonra aralık zamanlayıcı durmaz , bu nedenle print("Running: \(timer) ")birkaç satır koddan sonra bile doğru zamanı verecektir.

Aşağıda, RunningTimer kodu verilmiştir. Swift 2.1 için test edilmiştir:

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

Kolay kullanım için bir tamamlama bloğuna sarın.

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

Bu benim bulduğum pasaj ve Swift 4 ile Macbook'umda benim için çalışıyor gibi görünüyor.

Başka sistemlerde hiç test edilmemişti ama yine de paylaşmaya değer olduğunu düşündüm.

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

İşte nasıl kullanılacağına dair bir örnek:

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

Başka bir yol da bunu daha açık bir şekilde yapmaktır:

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

Ben böyle yazdım.

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

Bir algoritmayı ölçmek için onu böyle kullanın .

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

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

O zaman ne kadar doğru? Çünkü daha önce her 0.1 saniyede bir güncelleme yapmak için zamanlayıcı kullandım. Bu cevap ve bu cevaptan zamanlayıcı ve sonuçla biri 0.1 saniye zamanlayıcı ile daha sonra olmasıdır karşılaştırıldığında ..
Maksim Kniazev

0

Temel işlev zamanlaması için statik Swift3 sınıfı. Her zamanlayıcıyı isme göre takip edecektir. Ölçmeye başlamak istediğiniz noktada bunu şöyle adlandırın:

Stopwatch.start(name: "PhotoCapture")

Geçen süreyi yakalamak ve yazdırmak için bunu arayın:

Stopwatch.timeElapsed(name: "PhotoCapture")

Bu çıktı: *** PhotoCapture geçen ms: 1402.415125 Nano kullanmak istiyorsanız bir "useNanos" parametresi vardır. Lütfen gerektiği gibi değiştirmekten çekinmeyin.

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

}


İle olan bütün çalışmalar mach_timebase_infosen mi daha şimdiden daha uygulanmaktadır kaynak koduna ait ProcessInfo.processInfo.systemUptime. Yani basitçe yapın watches[name] = ProcessInfo.processInfo.systemUptime. Ve * TimeInterval(NSEC_PER_MSEC)nano istiyorsanız.
Cœur

0

Dayanarak Franklin Yu cevap ve Coeur yorumlarla

ayrıntılar

  • Xcode 10.1 (10B61)
  • Swift 4.2

1.Çözüm

_ (Ölçmek :)

2.Çözüm

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

Çözüm 2'nin kullanımı

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

Neden değişken uygulamaları kullanmamız gerektiğinden emin değilim. DateHerhangi bir şeyi ölçmek için kullanmak son derece cesaret kırıcıdır (ancak systemUptimeveya clock()sorun yoktur). Testlere gelince, biz measure(_:)zaten yaptık .
Cœur

1
Başka bir not: Kapatma neden isteğe bağlı hale getiriliyor?
Cœur

@ Doğru Cœur! Yorumlarınız için teşekkürler. Gönderiyi daha sonra güncelleyeceğim.
Vasily Bodnarchuk
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.