Вы случайно спрашиваете, потому что хотите узнать, что можно оптимизировать, чтобы сделать это быстрее?
Майк Данлавей
1
Да, я использую UIWebView, который загружает некоторые страницы. Я хочу , чтобы оптимизировать pageloading путем проверки времени метод должен загрузить страницу 1 на странице 10.
@BradLarson Несмотря на то, что он выглядит дубликатом, другой вопрос имеет лучшие ответы, то есть там выдающиеся ответы не предлагают использовать (неправильный) NSDate, но вместо этого хорошо объясняет, почему NSDate - неправильный способ сделать это для этой цели.
Томас Темпельманн
Ответы:
437
NSDate*methodStart =[NSDate date];/* ... Do whatever you need to do ... */NSDate*methodFinish =[NSDate date];NSTimeInterval executionTime =[methodFinish timeIntervalSinceDate:methodStart];NSLog(@"executionTime = %f", executionTime);
Swift:
let methodStart =NSDate()/* ... Do whatever you need to do ... */
let methodFinish =NSDate()
let executionTime = methodFinish.timeIntervalSinceDate(methodStart)
print("Execution time: \(executionTime)")
Swift3:
let methodStart =Date()/* ... Do whatever you need to do ... */
let methodFinish =Date()
let executionTime = methodFinish.timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")
Прост в использовании и имеет точность до миллисекунды.
Вы можете записать это значение с помощью% f - NSLog ("executeTime =% f", executeTime);
Тони
1
@ Тони, ты забыл @,NSLog(@"executionTime = %f", executionTime);
Джон Риселвато
6
Я только что сравнил NSDateи mach_absolute_time()на уровне около 30 мс. 27 против 29, 36 против 39, 43 против 45. NSDateМне было проще пользоваться, и результаты были достаточно схожими, чтобы не беспокоиться mach_absolute_time().
Неванский король
5
Все, что основано на NSDate, небезопасно для измерения прошедшего времени, потому что время может прыгать, даже назад. Гораздо более безопасный способ - использовать mach_absolute_time, как показано во многих других ответах здесь. Этот должен быть опущен за плохой пример. См. Также соответствующий ответ, который объясняет все это более подробно: stackoverflow.com/a/30363702/43615
Томас Темпельманн
252
Вот два однострочных макроса, которые я использую:
То, что делает это настолько хорошим, - то, что тик-так - такая запоминающаяся фраза, что регистрация почти не требует мысли.
Джон Риселвато,
30
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])заставляет этот ответ также возвращать, в какой функции использовался таймер. Я нашел это полезным, если использовал TICK TOCK для измерения времени нескольких функций.
golmschenk
3
Отличная идея @golmschenk! Вы также можете посмотреть __PRETTY_FUNCTION__и, __LINE__если вы хотите более подробную информацию.
Рон
50
Для детальной синхронизации в OS X вы должны использовать mach_absolute_time( )объявленный в <mach/mach_time.h>:
#include<mach/mach_time.h>#include<stdint.h>// Do some stuff to setup for timingconstuint64_t startTime = mach_absolute_time();// Do some stuff that you want to timeconstuint64_t endTime = mach_absolute_time();// Time elapsed in Mach time units.constuint64_t elapsedMTU = endTime - startTime;// Get information for converting from MTU to nanosecondsmach_timebase_info_data_t info;if(mach_timebase_info(&info))
handleErrorConditionIfYoureBeingCareful();// Get elapsed time in nanoseconds:constdouble elapsedNS =(double)elapsedMTU *(double)info.numer /(double)info.denom;
Конечно, применяются обычные предостережения о мелкозернистых измерениях; вам, вероятно, лучше всего многократно вызывать тестируемую процедуру и усреднять / брать минимум / какую-то другую форму обработки.
Кроме того, обратите внимание, что может оказаться более полезным профилировать приложение, запущенное с помощью такого инструмента, как Shark. Это не даст вам точную информацию о времени, но скажет, какой процент времени приложения тратится, где, что часто более полезно (но не всегда).
Пытаетесь заставить это работать в Свифте ... есть предложения?
zumzum
1
«Нельзя просто ... преобразовать в Свифта» - Нед Старк
stonedauwg
@zumzum Смотрите мой ответ для примера, как это сделать в Swift.
JBG
23
Есть удобная обёртка для mach_absolute_time()- это CACurrentMediaTime()функция.
В отличие от NSDateили CFAbsoluteTimeGetCurrent()смещений,
mach_absolute_time()и CACurrentMediaTime()основаны на внутренних часах хоста, точном одноатомном измерении и не подвержены изменениям внешнего эталона времени, например, вызванного часовыми поясами, переходом на летнее время или дополнительными секундами.
ObjC
CFTimeInterval startTime =CACurrentMediaTime();// Do your stuff hereCFTimeInterval endTime =CACurrentMediaTime();NSLog(@"Total Runtime: %g s", endTime - startTime);
стриж
let startTime =CACurrentMediaTime()// Do your stuff here
let endTime =CACurrentMediaTime()
print("Total Runtime: \(endTime - startTime) s")
С помощью этого класса StopWatch вы можете получить очень хорошее время (секунды.части секунд). Он использует высокоточный таймер в iPhone. Использование NSDate только даст вам точность (секунды). Эта версия разработана специально для autorelease и target-c. У меня есть версия C ++, а также при необходимости. Вы можете найти версию C ++ здесь .
У класса есть статический stopWatchметод, который возвращает автоматически выпущенный объект.
Как только вы позвоните start, используйте secondsметод, чтобы получить истекшее время. Звоните startснова, чтобы перезапустить его. Или stopостановить это. Вы все еще можете прочитать время (звонок seconds) в любое время после звонка stop.
CLOCKS_PER_SEC на iPhone - крайне неточное значение.
mxcl
1
Хорошо знать. Я бы использовал ответ Мэтью, если бы мне пришлось сделать это сейчас.
Дэвид Канарек
2
Пример точной синхронизации с использованием mach_absolute_time()в Swift 4:
let start = mach_absolute_time()// do something
let elapsedMTU = mach_absolute_time()- start
var timebase = mach_timebase_info()if mach_timebase_info(&timebase)==0{
let elapsed =Double(elapsedMTU)*Double(timebase.numer)/Double(timebase.denom)
print("render took \(elapsed)")}else{
print("timebase error")}
Хорошо, если ваша цель - выяснить, что вы можете исправить, чтобы сделать это быстрее, это немного другая цель. Измерение времени, которое занимают функции, - хороший способ выяснить, изменилось ли то, что вы сделали, но чтобы узнать, что делать, вам нужна другая техника. Это то, что я рекомендую , и я знаю, что вы можете сделать это на iPhone.
Изменить: рецензенты предложили мне разработать ответ, поэтому я пытаюсь придумать краткий способ сказать это.
Ваша общая программа занимает достаточно времени, чтобы беспокоить вас. Предположим, это N секунд.
Вы предполагаете, что можете ускорить это. Единственный способ сделать это - заставить его не делать то, что он делает за это время, что составляет m секунд.
Вы изначально не знаете, что это за вещь. Вы можете догадаться, как и все программисты, но это может быть что-то другое. Что бы это ни было, вот как это можно найти:
Поскольку эта вещь, какой бы она ни была, учитывает долю m / N времени, это означает, что если вы остановите ее наугад, вероятность того, что вы это поймете, будет равна m / N. Конечно, он может делать что-то еще, но сделайте паузу и посмотрите, что он делает.
Теперь сделай это снова. Если вы видите, что он делает то же самое снова, вы можете быть более подозрительным.
Сделайте это 10 раз или 20. Теперь, если вы видите, что он делает какую-то конкретную вещь (независимо от того, как вы это описываете) в нескольких паузах, от которой вы можете избавиться, вы знаете две вещи. Вы очень точно знаете, сколько времени это занимает, но вы точно знаете , что нужно исправить.
Если вы также хотите точно знать , сколько времени будет сэкономлено, это легко. Измерьте это прежде, исправьте это, и измерьте это после. Если вы действительно разочарованы, отмените исправление.
Вы видите, как это отличается от измерения? Это нахождение, а не измерение . Большая часть профилирования основана на измерении как можно точнее того, сколько времени уходит, как будто это важно, и решает проблему определения того, что необходимо исправить. Профилирование не находит всех проблем, но этот метод находит все проблемы, и проблемы, которые вы не находите, причиняют вам боль.
Вот другой способ, в Swift, сделать это с помощью ключевого слова defer
func methodName(){
let methodStart =Date()
defer {
let executionTime =Date().timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")}// do your stuff here}
Из документов Apple : оператор defer используется для выполнения кода непосредственно перед передачей управления программой за пределы области действия, в которой появляется оператор defer.
Это похоже на блок try / finally с преимуществом группирования соответствующего кода.
Я использую это в моей библиотеке утилит ( Swift 4.2 ):
publicclassPrintTimer{
let start =Date()
let name:Stringpublic init(file:String=#file, line:Int=#line, function:String=#function, name:String?=nil){
let file = file.split(separator:"/").last!
self.name = name ??"\(file):\(line) - \(function)"}public func done(){
let end =Date()
print("\(self.name) took \((end.timeIntervalSinceReferenceDate - self.start.timeIntervalSinceReferenceDate).roundToSigFigs(5)) s.")}}
... затем вызовите метод, как:
func myFunctionCall(){
let timer =PrintTimer()// ...
timer.done()}
... который в свою очередь выглядит в консоли после запуска:
MyFile.swift:225- myFunctionCall() took 1.8623 s.
Не так кратко, как TICK / TOCK выше, но достаточно ясно, чтобы увидеть, что он делает, и автоматически включает в себя то, что рассчитывается (по файлу, строке в начале метода и имени функции). Очевидно, что если бы я хотел больше подробностей (например, если я не просто синхронизирую вызов метода, как это обычно бывает, а вместо этого синхронизирую блок внутри этого метода), я могу добавить параметр "name =" Foo "" в инициализации PrintTimer назвать это что-то помимо значений по умолчанию.
Поскольку вы хотите оптимизировать время перехода с одной страницы на другую в UIWebView, не значит ли это, что вы действительно хотите оптимизировать Javascript, используемый при загрузке этих страниц?
Для этого я бы посмотрел на профилировщик WebKit, о котором говорилось здесь:
Другой подход заключается в том, чтобы начать с высокого уровня и подумать, как можно спроектировать соответствующие веб-страницы, чтобы минимизировать время загрузки, используя загрузку страниц в стиле AJAX вместо того, чтобы каждый раз обновлять весь веб-просмотр.
struct TIME {static var ti = mach_timebase_info()static var k:Double=1static var mach_stamp:Double{if ti.denom ==0{
mach_timebase_info(&ti)
k =Double(ti.numer)/Double(ti.denom)*1e-6}returnDouble(mach_absolute_time())* k
}static var stamp:Double{returnNSDate.timeIntervalSinceReferenceDate()*1000}}do{
let mach_start = TIME.mach_stamp
usleep(200000)
let mach_diff = TIME.mach_stamp - mach_start
let start = TIME.stamp
usleep(200000)
let diff = TIME.stamp - start
print(mach_diff, diff)}
Вот решение Swift 3 для разделения кода в любом месте, чтобы найти длительный процесс.
var increment:Int=0
var incrementTime =NSDate()structInstrumentation{
var title:String
var point:Int
var elapsedTime:Double
init(_ title:String, _ point:Int, _ elapsedTime:Double){
self.title = title
self.point = point
self.elapsedTime = elapsedTime
}}
var elapsedTimes =[Instrumentation]()
func instrument(_ title:String){
increment +=1
let incrementedTime =-incrementTime.timeIntervalSinceNow
let newPoint =Instrumentation(title, increment, incrementedTime)
elapsedTimes.append(newPoint)
incrementTime =NSDate()}
Использование: -
instrument("View Did Appear")
print("ELAPSED TIMES \(elapsedTimes)")
многие ответы странные и на самом деле не дают результата в миллисекундах (но в секундах или чем-то еще):
вот что я использую, чтобы получить MS (миллисекунды):
Swift:
let startTime =NSDate().timeIntervalSince1970 *1000// your Swift code
let endTimeMinusStartTime =NSDate().timeIntervalSince1970 *1000- startTime
print("time code execution \(endTimeMinStartTime) ms")
Ответы:
Swift:
Swift3:
Прост в использовании и имеет точность до миллисекунды.
источник
NSLog(@"executionTime = %f", executionTime);
NSDate
иmach_absolute_time()
на уровне около 30 мс. 27 против 29, 36 против 39, 43 против 45.NSDate
Мне было проще пользоваться, и результаты были достаточно схожими, чтобы не беспокоитьсяmach_absolute_time()
.Вот два однострочных макроса, которые я использую:
Используйте это так:
источник
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])
заставляет этот ответ также возвращать, в какой функции использовался таймер. Я нашел это полезным, если использовал TICK TOCK для измерения времени нескольких функций.__PRETTY_FUNCTION__
и,__LINE__
если вы хотите более подробную информацию.Для детальной синхронизации в OS X вы должны использовать
mach_absolute_time( )
объявленный в<mach/mach_time.h>
:Конечно, применяются обычные предостережения о мелкозернистых измерениях; вам, вероятно, лучше всего многократно вызывать тестируемую процедуру и усреднять / брать минимум / какую-то другую форму обработки.
Кроме того, обратите внимание, что может оказаться более полезным профилировать приложение, запущенное с помощью такого инструмента, как Shark. Это не даст вам точную информацию о времени, но скажет, какой процент времени приложения тратится, где, что часто более полезно (но не всегда).
источник
Есть удобная обёртка для
mach_absolute_time()
- этоCACurrentMediaTime()
функция.ObjC
стриж
источник
NSDate
.В Swift я использую:
В моем Macros.swift я только что добавил
теперь вы можете просто позвонить куда угодно
источник
\(-startTime.timeIntervalSinceNow)
(обратите внимание на негатив)Я знаю, что это старый, но даже я обнаружил, что снова прошёл мимо него, поэтому я решил представить свой вариант здесь.
Лучше всего проверить мой пост на этом блоге: Время в Objective-C: секундомер
По сути, я написал класс, который перестает смотреть в основном виде, но инкапсулирован так, что вам нужно только сделать следующее:
И вы в конечном итоге:
в журнале ...
Снова, проверьте мой пост для немного больше или загрузите его здесь: MMStopwatch.zip
источник
Я использую макросы на основе решения Рона .
Для строк кода:
мы увидим в консоли что-то вроде: TIME1: 0.096618
источник
Я использую очень минимальную, одностраничную реализацию класса, вдохновленную кодом из этого поста :
Использование этого очень просто:
[DBGStopwatch start:@"slow-operation"];
в начале[DBGStopwatch stop:@"slow-operation"];
после финиша, чтобы получить времяисточник
С помощью этого класса StopWatch вы можете получить очень хорошее время (секунды.части секунд). Он использует высокоточный таймер в iPhone. Использование NSDate только даст вам точность (секунды). Эта версия разработана специально для autorelease и target-c. У меня есть версия C ++, а также при необходимости. Вы можете найти версию C ++ здесь .
StopWatch.h
StopWatch.m
У класса есть статический
stopWatch
метод, который возвращает автоматически выпущенный объект.Как только вы позвоните
start
, используйтеseconds
метод, чтобы получить истекшее время. Звонитеstart
снова, чтобы перезапустить его. Илиstop
остановить это. Вы все еще можете прочитать время (звонокseconds
) в любое время после звонкаstop
.Пример в функции (время выполнения вызова)
источник
Я использую этот код:
источник
Я использую это:
Но я не уверен насчет CLOCKS_PER_SEC на iPhone. Вы можете оставить это.
источник
Пример точной синхронизации с использованием
mach_absolute_time()
в Swift 4:источник
Хорошо, если ваша цель - выяснить, что вы можете исправить, чтобы сделать это быстрее, это немного другая цель. Измерение времени, которое занимают функции, - хороший способ выяснить, изменилось ли то, что вы сделали, но чтобы узнать, что делать, вам нужна другая техника. Это то, что я рекомендую , и я знаю, что вы можете сделать это на iPhone.
Изменить: рецензенты предложили мне разработать ответ, поэтому я пытаюсь придумать краткий способ сказать это.
Ваша общая программа занимает достаточно времени, чтобы беспокоить вас. Предположим, это N секунд.
Вы предполагаете, что можете ускорить это. Единственный способ сделать это - заставить его не делать то, что он делает за это время, что составляет m секунд.
Вы изначально не знаете, что это за вещь. Вы можете догадаться, как и все программисты, но это может быть что-то другое. Что бы это ни было, вот как это можно найти:
Поскольку эта вещь, какой бы она ни была, учитывает долю m / N времени, это означает, что если вы остановите ее наугад, вероятность того, что вы это поймете, будет равна m / N. Конечно, он может делать что-то еще, но сделайте паузу и посмотрите, что он делает.
Теперь сделай это снова. Если вы видите, что он делает то же самое снова, вы можете быть более подозрительным.
Сделайте это 10 раз или 20. Теперь, если вы видите, что он делает какую-то конкретную вещь (независимо от того, как вы это описываете) в нескольких паузах, от которой вы можете избавиться, вы знаете две вещи. Вы очень точно знаете, сколько времени это занимает, но вы точно знаете , что нужно исправить.
Если вы также хотите точно знать , сколько времени будет сэкономлено, это легко. Измерьте это прежде, исправьте это, и измерьте это после. Если вы действительно разочарованы, отмените исправление.
Вы видите, как это отличается от измерения? Это нахождение, а не измерение . Большая часть профилирования основана на измерении как можно точнее того, сколько времени уходит, как будто это важно, и решает проблему определения того, что необходимо исправить. Профилирование не находит всех проблем, но этот метод находит все проблемы, и проблемы, которые вы не находите, причиняют вам боль.
источник
Вот другой способ, в Swift, сделать это с помощью ключевого слова defer
Из документов Apple : оператор defer используется для выполнения кода непосредственно перед передачей управления программой за пределы области действия, в которой появляется оператор defer.
Это похоже на блок try / finally с преимуществом группирования соответствующего кода.
источник
Я использую это в моей библиотеке утилит ( Swift 4.2 ):
... затем вызовите метод, как:
... который в свою очередь выглядит в консоли после запуска:
Не так кратко, как TICK / TOCK выше, но достаточно ясно, чтобы увидеть, что он делает, и автоматически включает в себя то, что рассчитывается (по файлу, строке в начале метода и имени функции). Очевидно, что если бы я хотел больше подробностей (например, если я не просто синхронизирую вызов метода, как это обычно бывает, а вместо этого синхронизирую блок внутри этого метода), я могу добавить параметр "name =" Foo "" в инициализации PrintTimer назвать это что-то помимо значений по умолчанию.
источник
Поскольку вы хотите оптимизировать время перехода с одной страницы на другую в UIWebView, не значит ли это, что вы действительно хотите оптимизировать Javascript, используемый при загрузке этих страниц?
Для этого я бы посмотрел на профилировщик WebKit, о котором говорилось здесь:
http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/
Другой подход заключается в том, чтобы начать с высокого уровня и подумать, как можно спроектировать соответствующие веб-страницы, чтобы минимизировать время загрузки, используя загрузку страниц в стиле AJAX вместо того, чтобы каждый раз обновлять весь веб-просмотр.
источник
источник
Вот решение Swift 3 для разделения кода в любом месте, чтобы найти длительный процесс.
Использование: -
Пример вывода: -
источник
многие ответы странные и на самом деле не дают результата в миллисекундах (но в секундах или чем-то еще):
вот что я использую, чтобы получить MS (миллисекунды):
Swift:
Objective-C:
источник
Для Swift 4 добавьте делегата в свой класс:
Добавьте к нашему классу:
Затем добавьте в свой класс:
Когда вы хотите рассчитать время, начните с:
И конец:
источник