Swiftで関数を実行するために経過した時間をどのように測定できますか?次のように経過時間を表示しようとしています:「経過時間は.05秒です」。 Javaで 、System.nanoTime()を使用できること、これを達成するためにSwiftで利用可能な同等のメソッドはありますか?
サンプルプログラムをご覧ください。
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");
}
ここに、測定するために書いたSwift関数があります Project Euler Swiftの問題
Swift 3現在、「Swiftified」であるGrand Central Dispatchのバージョンがあります。したがって、おそらく正しい答えは DispatchTime API を使用することです。
私の機能は次のようになります:
// 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
}
Swift 1および2の場合、私の関数は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
}
タイミング関数にNSdateを使用することはお勧めできません。「外部時刻参照との同期またはクロックの明示的なユーザー変更により、システム時刻が減少する場合があります。」。
これは、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
}
}
}
次のように使用できます。
let timer = ParkBenchTimer()
// ... a long runnig task ...
println("The task took \(timer.stop()) seconds.")
clock
、 ProcessInfo.systemUptime
、またはDispatchTime
を使用します。私が知る限り、経過時間を測定するための少なくとも10の方法があります。
ProcessInfo.systemUptime
。mach_absolute_time
とmach_timebase_info
( this answer で述べたように).clock()
in POSIX標準 。times()
in POSIX標準 。 (ユーザー時間とシステム時間を考慮する必要があり、子プロセスが関与しているため、複雑すぎます。)DispatchTime
(Mach time APIのラッパー)。受け入れられた回答でJeremyPが言及しています。CACurrentMediaTime()
。(メトリックにこれらを使用しないでください。以下を参照してください)
NSDate
/Date
他の人が述べたように。CFAbsoluteTime
他の人が述べたように。DispatchWallTime
。gettimeofday()
in POSIX標準 。オプション1、2、および3については、以下で詳しく説明します。
do {
let info = ProcessInfo.processInfo
let begin = info.systemUptime
// do something
let diff = (info.systemUptime - begin)
}
ここで、diff:NSTimeInterval
は秒単位の経過時間です。
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:Double
はナノ秒単位の経過時間です。
do {
let begin = clock()
// do something
let diff = Double(clock() - begin) / Double(CLOCKS_PER_SEC)
}
ここで、diff:Double
は秒単位の経過時間です。
CFAbsoluteTimeGetCurrent
のドキュメント:
この関数を繰り返し呼び出しても、結果が単調に増加することは保証されません。
理由は、Javaの currentTimeMillis
vs nanoTime
に似ています :
他の目的に使用することはできません。その理由は、完璧なコンピューターの時計はないということです。常にドリフトし、ときどき修正する必要があります。この修正は手動で行われるか、ほとんどのマシンの場合、システムクロック(「ウォールクロック」)に対して小さな修正を実行して継続的に発行するプロセスがあります。これらは頻繁に発生する傾向があります。うるう秒があるたびに、別のそのような修正が行われます。
ここで、CFAbsoluteTime
は、起動時間ではなく実時間を提供します。 NSDate
も実時間です。
Swift 4最短回答:
let startingPoint = Date()
// ... intensive task
print("\(startingPoint.timeIntervalSinceNow * -1) seconds elapsed")
1.02107906341553 seconds seconds(もちろん、時間はタスクによって異なります。この測定の10進精度レベルを確認するために表示しています).
Swift 4の誰かがこれから役立つことを願っています!
let start = NSDate()
for index in 1...10000 {
// do nothing
}
let elapsed = start.timeIntervalSinceNow
// elapsed is a negative value.
呼び出しを測定するためのtime
関数を作成できます。 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.")
}
この関数を使用すると、結果と経過時間の文字列の説明を含むタプルを返すtime (isPrime(7))
のように呼び出すことができます。
経過時間のみを希望する場合は、これを行うことができますtime (isPrime(7)).duration
クロージャを使用して実行時間を測定するためのシンプルなヘルパー関数。
func printExecutionTime(withTag tag: String, of closure: () -> ()) {
let start = CACurrentMediaTime()
closure()
print("#\(tag) - execution took \(CACurrentMediaTime() - start) seconds")
}
使用法:
printExecutionTime(withTag: "Init") {
// Do your work here
}
結果:#Init - execution took 1.00104497105349 seconds
この関数をコピーして貼り付けてください。 Swiftで書かれています5. JeremyPをここにコピーします。
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")
}
のように使用します
calculateTime {
exampleFunc()// function whose execution time to be calculated
}
最も簡単な答えをしようとしています:
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
注
startTime
およびendTime
は、タイプ TimeInterval
であり、これはtypealias
の単なるDouble
であるため、Int
などに簡単に変換できます。時間はミリ秒未満の精度で秒単位で測定されます。DateInterval
も参照してください。実際の開始時刻と終了時刻が含まれています。私はこれを使用します:
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_;
}
}
以前に投稿したものよりも正確かどうかはわかりません。しかし、秒には多くの小数があり、swap()を使用するQuickSortとswap urselfの実装などのアルゴリズムの小さなコード変更をキャッチするようです。
パフォーマンスをテストするときは、ビルドの最適化を忘れずに行ってください。
nanosecondsを測定できますこの:
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)")
簡単に使用できるように、完了ブロックでラップします。
public class func secElapsed(completion: () -> Void) {
let startDate: NSDate = NSDate()
completion()
let endDate: NSDate = NSDate()
let timeInterval: Double = endDate.timeIntervalSinceDate(startDate)
println("seconds: \(timeInterval)")
}
Klaasからアイデアを借りて、実行時間とインターバル時間を測定する軽量の構造体を作成しました。
コードの使用:
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
印刷機能は経過時間を示すため、停止機能を呼び出す必要はありません。経過時間を取得するために繰り返し呼び出される場合があります。ただし、コードの特定のポイントでタイマーを停止するには、timer.stop()
を使用します。秒単位で時間を返す場合もあります。let seconds = timer.stop()
タイマーが停止すると、インターバルタイマーは停止します。したがって、print("Running: \(timer) ")
は数行後でも正しい時間を提供しますコードの。
以下は、RunningTimerのコードです。 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"}
}
}
これは私が思いついたスニペットであり、Swift 4を使用してMacbookで動作するようです。
他のシステムでテストしたことはありませんが、とにかく共有する価値があると思いました。
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())
}
以下に使用方法の例を示します。
let t1 = monotonic_now()
// .. some code to run ..
let elapsed = seconds_elapsed(since: t1)
print("Time elapsed: \(elapsed*1000)ms")
もう1つの方法は、より明示的に行うことです。
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)")
これが私が書いた方法です。
func measure<T>(task: () -> T) -> Double {
let startTime = CFAbsoluteTimeGetCurrent()
task()
let endTime = CFAbsoluteTimeGetCurrent()
let result = endTime - startTime
return result
}
アルゴリズムを測定するにはseそのように。
let time = measure {
var array = [2,4,5,2,5,7,3,123,213,12]
array.sorted()
}
print("Block is running \(time) seconds.")
基本的な機能タイミングのための静的Swift3クラス。各タイマーを名前で追跡します。測定を開始するポイントで次のように呼び出します。
Stopwatch.start(name: "PhotoCapture")
これを呼び出して、経過時間をキャプチャして印刷します。
Stopwatch.timeElapsed(name: "PhotoCapture")
出力は次のとおりです。*** PhotoCapture必要に応じて自由に変更してください。
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))")
}
}
}