Swift에서 경과 시간 측정
Swift에서 함수를 실행하는 데 걸린 시간을 어떻게 측정 할 수 있습니까? 다음과 같이 경과 시간을 표시하려고합니다. "경과 시간은 .05 초입니다". 톱 있음을 자바로 , 우리는 System.nanoTime ()를 사용하여 동등한 방법은 이러한 목표를 달성하기 위해 스위프트에서 사용할 수 있습니다 무엇입니까?
샘플 프로그램을 살펴보십시오 :
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 가지입니다.
Monotonic Clock 기반 :
ProcessInfo.systemUptime
.mach_absolute_time
과mach_timebase_info
에서 언급 한 바와 같이 이 답변 .clock()
에서 POSIX 표준 .times()
에서 POSIX 표준 . (사용자 시간과 시스템 시간을 고려해야하고 하위 프로세스가 관련되어 있으므로 너무 복잡합니다.)DispatchTime
(Mach time API를 둘러싼 래퍼) JeremyP가 수락 한 답변에서 언급했습니다.CACurrentMediaTime()
.
벽시계 기반 :
(측정 항목에는 절대 사용하지 마세요. 아래 이유를 참조하세요.
NSDate
/Date
다른 사람들이 언급했듯이.CFAbsoluteTime
다른 사람들이 언급했듯이.DispatchWallTime
.gettimeofday()
에서 POSIX 표준 .
옵션 1, 2 및 3은 아래에 자세히 설명되어 있습니다.
옵션 1 : Foundation의 Process Info API
do {
let info = ProcessInfo.processInfo
let begin = info.systemUptime
// do something
let diff = (info.systemUptime - begin)
}
여기서 diff:NSTimeInterval
초 의해 경과 시간이다.
옵션 2 : Mach C API
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
나노초 단위의 경과 시간은 어디에 있습니까 ?
옵션 3 : POSIX 클록 API
do {
let begin = clock()
// do something
let diff = Double(clock() - begin) / Double(CLOCKS_PER_SEC)
}
여기서 diff:Double
초 의해 경과 시간이다.
경과 시간에 대한 벽시계 시간이 아닌 이유는 무엇입니까?
문서에서 CFAbsoluteTimeGetCurrent
:
이 함수에 대한 반복적 인 호출은 단조롭게 증가하는 결과를 보장하지 않습니다.
이유는 Java의 currentTimeMillis
vsnanoTime
와 유사합니다 .
다른 용도로 사용할 수 없습니다. 그 이유는 컴퓨터의 시계가 완벽하지 않기 때문입니다. 항상 표류하며 때때로 수정해야합니다. 이 수정은 수동으로 이루어 지거나 대부분의 컴퓨터에서 실행되고 시스템 시계 ( "벽 시계")에 대한 작은 수정을 지속적으로 발행하는 프로세스가 있습니다. 이것은 자주 일어나는 경향이 있습니다. 또 다른 수정은 윤초가있을 때마다 발생합니다.
여기 CFAbsoluteTime
에서는 시작 시간 대신 벽시계 시간을 제공합니다. NSDate
벽시계 시간이기도합니다.
Swift 4 짧은 답변 :
let startingPoint = Date()
// ... intensive task
print("\(startingPoint.timeIntervalSinceNow * -1) seconds elapsed")
1.02107906341553 초가 경과 한 것과 같은 것을 인쇄 할 것 입니다 (물론 시간은 작업에 따라 다를 수 있습니다.이 측정에 대한 십진 정밀도 수준을 볼 수 있도록 보여 드리겠습니다).
지금부터 Swift 4의 누군가에게 도움이되기를 바랍니다!
let start = NSDate()
for index in 1...10000 {
// do nothing
}
let elapsed = start.timeIntervalSinceNow
// elapsed is a negative value.
time
호출을 측정 하는 함수를 만들 수 있습니다 . 나는 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.")
}
이 함수를 사용하면 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
다음 과 같이 나노초 를 측정 할 수 있습니다 .
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 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와 같은 알고리즘에서 작은 코드 변경 사항을 포착하는 것 같습니다.
성능을 테스트 할 때 빌드 최적화를 강화하는 것을 잊지 마십시오.
가장 간단한 대답을위한 나의 시도는 다음과 같습니다.
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
forDouble
일 뿐이 므로 쉽게 변환 할 수Int
있습니다. 시간은 밀리 초 미만의 정밀도로 초 단위로 측정됩니다.DateInterval
실제 시작 및 종료 시간이 포함 된을 참조하십시오 .- 1970 년 이후의 시간을 사용하는 것은 Java 타임 스탬프 와 유사합니다 .
이 기능을 복사하여 붙여 넣기 만하면됩니다. 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
}
나는 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"}
}
}
쉽게 사용할 수 있도록 완성 블록에 포장하십시오.
public class func secElapsed(completion: () -> Void) {
let startDate: NSDate = NSDate()
completion()
let endDate: NSDate = NSDate()
let timeInterval: Double = endDate.timeIntervalSinceDate(startDate)
println("seconds: \(timeInterval)")
}
이것은 내가 생각해 낸 스 니펫이며 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")
또 다른 방법은 더 명시 적으로 수행하는 것입니다.
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")
이것이 내가 쓴 방법입니다.
func measure<T>(task: () -> T) -> Double {
let startTime = CFAbsoluteTimeGetCurrent()
task()
let endTime = CFAbsoluteTimeGetCurrent()
let result = endTime - startTime
return result
}
알고리즘을 측정하려면 그렇게 사용 하십시오.
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 elapsed ms : 1402.415125 나노를 사용하려는 경우 "useNanos"매개 변수가 있습니다. 필요에 따라 자유롭게 변경하십시오.
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))")
}
}
}
을 바탕으로 프랭클린 유 대답과 쾨르의 의견
세부
- Xcode 10.1 (10B61)
- 스위프트 4.2
해결책 1
해결 방법 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)
}
}
솔루션 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)")
참고 URL : https://stackoverflow.com/questions/24755558/measure-elapsed-time-in-swift
'developer tip' 카테고리의 다른 글
테이블보기 결과가 없으면 화면에 "결과 없음"표시 (0) | 2020.08.08 |
---|---|
Postgres-치명적 : 데이터베이스 파일이 서버와 호환되지 않습니다. (0) | 2020.08.08 |
솔루션을 열 때 Visual Studio 2013이 중단됨 (0) | 2020.08.08 |
모든 첫 글자를 대문자로 변환하고 각 단어에 대해 더 낮게 유지 (0) | 2020.08.08 |
Android Studio : Android SDK 소스를 연결하는 방법은 무엇입니까? (0) | 2020.08.08 |