경과시간 측정(Swift)
Swift에서 기능을 실행하는 데 걸리는 시간을 어떻게 측정할 수 있습니까?경과시간은 다음과 같이 표시하려고 합니다. "Excessed time is .05 seconds"Java에서 System.nano Time()을 사용할 수 있는 것을 보았습니다만, Swift에서 이와 동등한 방법을 사용할 수 있습니까?
샘플 프로그램을 확인해 주십시오.
func isPrime(_ 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) {
print("Prime number")
} else {
print("NOT a prime number")
}
갱신하다
Swift 5.7에서는 아래의 모든 것이 쓸모 없게 됩니다.Swift 5.7은 여기에 요구되는 기능을 정확히 수행하도록 설계된 시계 개념을 도입했다.
가지 .Clock ★★★★★ContinuousClock ★★★★★★★★★★★★★★★★★」SuspendingClock전자는 시스템이 정지되어 있을 때, 후자는 정지하고 있지 않을 때 계속 똑딱거린다.
다음은 Swift 5.7에서 수행하는 작업의 예입니다.
func doSomething()
{
for i in 0 ..< 1000000
{
if (i % 10000 == 0)
{
print(i)
}
}
}
let clock = ContinuousClock()
let result = clock.measure(doSomething)
print(result) // On my laptop, prints "0.552065882 seconds"
물론 폐쇄를 직접 측정할 수도 있습니다.
let clock = ContinuousClock()
let result = clock.measure {
for i in 0 ..< 1000000
{
if (i % 10000 == 0)
{
print(i)
}
}
}
print(result) // "0.534663798 seconds"
Pre Swift 5.7
Swift에서 프로젝트 오일러 문제를 측정하기 위해 쓴 Swift 함수가 있습니다.
Swift 3에서는 Grand Central Dispatch의 '스위프트' 버전이 있습니다.따라서 정답은 아마도 Dispatch Time 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를 사용하는 것은 권장되지 않습니다.「시스템 시간은, 외부 시간 참조와의 동기 또는 클럭의 명시적인 유저 변경에 의해서 감소하는 경우가 있습니다.」
은 편리하고 편리한 입니다.CoreFoundations:
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 ...
print("The task took \(timer.stop()) seconds.")
간단한 시작 시간에는 , 또는 를 사용합니다.
경과시간을 측정하는 방법은 적어도 10가지가 있는 것으로 알고 있습니다.
모노톤 클럭 기반:
- 를 클릭합니다
ProcessInfo.systemUptime. mach_absolute_time와 함께mach_timebase_info이 답변에 언급된 바와 같이clock()POSIX 규격에 준거하고 있습니다.times()(사용자 시간과 시스템 시간을 고려해야 하기 때문에 너무 복잡하며 하위 프로세스가 관련되어 있습니다.)DispatchTimeJeremyP가 수용된 답변에서 언급한 바와 같이 (Mach time API에 관한 래퍼).- 를 클릭합니다
CACurrentMediaTime().
벽시계 기반:
(측정지표에는 사용하지 마십시오.이유는 아래를 참조해 주세요.)
NSDate/Date른른른른른CFAbsoluteTime른른른른른- 를 클릭합니다
DispatchWallTime. gettimeofday()POSIX 규격에 준거하고 있습니다.
옵션 1, 2, 3은 아래에 자세히 설명되어 있습니다.
옵션 1: Foundation 프로세스 정보 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는 초단위의 경과시간입니다.
월클럭 시간은 경과된 시간으로 하지 않는 이유는 무엇입니까?
의 매뉴얼:
이 함수에 대한 콜이 반복된다고 해서 결과가 단조롭게 증가하는 것은 아닙니다.
이유는 Java의 vs와 비슷합니다.
다른 용도로는 사용할 수 없습니다.그 이유는 컴퓨터 시계가 완벽하지 않기 때문입니다.시계는 항상 어긋나기 때문에 때로는 교정이 필요합니다.이 수정은 수동으로 이루어지거나 대부분의 머신에서는 시스템 클럭('월클럭')에 작은 수정을 계속 실행하는 프로세스가 있습니다.이런 일은 자주 일어납니다.윤초가 있을 때마다 이러한 수정이 발생합니다.
서 ★★★★CFAbsoluteTime는 시작 시간이 아닌 벽시계 시간을 제공합니다. NSDate이치노
Swift 4 단답:
let startingPoint = Date()
// ... intensive task
print("\(startingPoint.timeIntervalSinceNow * -1) seconds elapsed")
1.02107906341553초의 경과 시간이 표시됩니다(물론 작업에 따라 시간은 달라집니다.이 측정의 소수점 정밀도 레벨을 표시해 드리겠습니다).
앞으로 Swift 4에 있는 누군가에게 도움이 되길 바랍니다!
갱신하다
코드 일부를 테스트하는 일반적인 방법을 원한다면 다음 스니펫을 제안합니다.
func measureTime(for closure: @autoclosure () -> Any) {
let start = CFAbsoluteTimeGetCurrent()
closure()
let diff = CFAbsoluteTimeGetCurrent() - start
print("Took \(diff) seconds")
}
사용.
measureTime(for: <insert method signature here>)
콘솔 로그
Took xx.xxxxx seconds
이 기능을 복사하여 붙여넣기만 하면 됩니다.swift 5로 작성.여기 제레미P 따라하고 있어
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 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
iOS 13이 새로운 API를 도입한 것 같습니다.DispatchTime그러면 두 타임스탬프 간의 차이를 수동으로 계산할 필요가 없어집니다.
let start: DispatchTime = .now()
heavyTaskToMeasure()
let duration = start.distance(to: .now())
print(duration)
// prints: nanoseconds(NUMBER_OF_NANOSECONDS_BETWEEN_TWO_TIMESTAMPS)
이 몇 , 이 는 """로 ..nanoseconds이치노
합니다.DispatchTimeInterval로로 합니다.TimeInterval신용장
extension TimeInterval {
init?(dispatchTimeInterval: DispatchTimeInterval) {
switch dispatchTimeInterval {
case .seconds(let value):
self = Double(value)
case .milliseconds(let value):
self = Double(value) / 1_000
case .microseconds(let value):
self = Double(value) / 1_000_000
case .nanoseconds(let value):
self = Double(value) / 1_000_000_000
case .never:
return nil
}
}
}
클로징으로 실행시간을 측정하기 위한 간단한 도우미 기능.
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_;
}
}
나는 그것이 이전에 게시된 것보다 더 정확한지 아닌지 모르겠다.단, seconds에는 소수점이 많아 QuickSort 등의 알고리즘에서 swap()을 사용하는 경우와 swap urself를 구현하는 경우 등의 작은 코드 변경을 포착할 수 있습니다.
성능을 테스트할 때는 빌드 최적화를 활성화해야 합니다.

가장 간단한 답변에 대한 저의 시도는 다음과 같습니다.
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의 타입으로 되어 있습니다.그것은typealias★★★★★★에Double수Int은 의 정밀도로 됩니다.시간은 밀리초 미만의 정밀도로 초 단위로 측정됩니다.- 또, 실제의 개시 시각과 종료 시각이 기재되어 있는 것도 참조해 주세요.
- 1970년 이후의 시간은 Java 타임스탬프와 비슷합니다.
경과시간/퍼포먼스를 체크하는 권장방법은measure에서 할 수 있는 XCTests.
코드 블록의 성능(따라서 실행/ 경과 시간)은 CPU 캐시 등의 영향을 받기 때문에 자체 측정 블록을 작성하는 것은 신뢰할 수 없습니다.
함수가 두 번째로 호출될 때 처음 호출될 때보다 더 빠를 수 있습니다. 단, 함수는 몇 % 다를 수 있습니다.따라서 "벤치마킹"은 한 번 실행함으로써 자체 폐쇄(여기서 모든 곳에 제공됨)를 사용함으로써 실제 사용자가 실제 실행 중인 코드와는 다른 결과를 얻을 수 있습니다.
measure함수는 코드 블록을 여러 번 호출하여 코드의 성능/실현 시간을 프로덕션에서 사용하는 것처럼 모방합니다(적어도 더 정확한 결과를 얻을 수 있습니다.
사용하기 쉽도록 완성 블록으로 포장합니다.
public class func secElapsed(completion: () -> Void) {
let startDate: NSDate = NSDate()
completion()
let endDate: NSDate = NSDate()
let timeInterval: Double = endDate.timeIntervalSinceDate(startDate)
println("seconds: \(timeInterval)")
}
기본 기능 타이밍을 위한 Static Swift3 클래스.이름별로 각 타이머를 추적합니다.측정을 시작할 지점에서 다음과 같이 호출합니다.
Stopwatch.start(name: "PhotoCapture")
이 호출을 통해 경과된 시간을 캡처하고 인쇄합니다.
Stopwatch.timeElapsed(name: "PhotoCapture")
출력은 다음과 같습니다.** PhotoCapture passed 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))")
}
}
}
스위프트 5 이상
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를 탑재한 맥북에서 사용할 수 있을 것 같습니다.
다른 시스템에서 테스트한 적은 없지만 공유할 가치가 있다고 생각했습니다.
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.")
Franklin Yu의 답변과 Cöur의 코멘트를 바탕으로 합니다.
세부 사항
- X코드 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)")
50, , .0부터는 Swift 5.7(macOS 13.0, iOS 16.0, watch OS 9.0, tvOS 16.0)을 사용할 수 .ContinuousClock 및measureblock: 객체를 반환합니다.초 단위 또는 애토초 단위로 측정된 시간(1×10초−18)을 포함하는 구성 요소가 있습니다.
let clock = ContinuousClock()
let duration = clock.measure {
// put here what you want to measure
}
print("Duration: \(duration.components.seconds) seconds")
print("Duration: \(duration.components.attoseconds) attoseconds")
언급URL : https://stackoverflow.com/questions/24755558/measure-elapsed-time-in-swift
'programing' 카테고리의 다른 글
| SQL Server: 여러 행을 하나의 행으로 결합 (0) | 2023.04.09 |
|---|---|
| Swift에서 HTTP 요청을 하는 방법은 무엇입니까? (0) | 2023.04.09 |
| 데이터베이스에 보기가 있는지 확인하려면 어떻게 해야 합니까? (0) | 2023.04.09 |
| 텍스트 파일의 행 끝을 확인하려면 어떻게 해야 합니까? (0) | 2023.04.09 |
| 코코아팟 프레임워크 버전을 확인하는 방법 (0) | 2023.04.09 |