Как вы проверяете время работы кода VBA?

95

Есть ли в VBA код, которым я могу обернуть функцию, которая сообщит мне, сколько времени потребовалось для запуска, чтобы я мог сравнить разное время работы функций?

Лэнс Робертс
источник

Ответы:

81

Если ваши функции не очень медленные, вам понадобится таймер с очень высоким разрешением. Самый точный из известных мне QueryPerformanceCounter. Google для получения дополнительной информации. Попробуйте вставить следующее в класс, назовите его CTimersay, затем вы можете создать экземпляр где-нибудь в глобальном масштабе и просто вызвать .StartCounterи.TimeElapsed

Option Explicit

Private Type LARGE_INTEGER
    lowpart As Long
    highpart As Long
End Type

Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As LARGE_INTEGER) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As LARGE_INTEGER) As Long

Private m_CounterStart As LARGE_INTEGER
Private m_CounterEnd As LARGE_INTEGER
Private m_crFrequency As Double

Private Const TWO_32 = 4294967296# ' = 256# * 256# * 256# * 256#

Private Function LI2Double(LI As LARGE_INTEGER) As Double
Dim Low As Double
    Low = LI.lowpart
    If Low < 0 Then
        Low = Low + TWO_32
    End If
    LI2Double = LI.highpart * TWO_32 + Low
End Function

Private Sub Class_Initialize()
Dim PerfFrequency As LARGE_INTEGER
    QueryPerformanceFrequency PerfFrequency
    m_crFrequency = LI2Double(PerfFrequency)
End Sub

Public Sub StartCounter()
    QueryPerformanceCounter m_CounterStart
End Sub

Property Get TimeElapsed() As Double
Dim crStart As Double
Dim crStop As Double
    QueryPerformanceCounter m_CounterEnd
    crStart = LI2Double(m_CounterStart)
    crStop = LI2Double(m_CounterEnd)
    TimeElapsed = 1000# * (crStop - crStart) / m_crFrequency
End Property
Майк Вудхаус
источник
2
Я реализовал это в Excel VBA (добавив накладные расходы, как указано в этой статье базы знаний : support.microsoft.com/kb/172338 . Это отлично сработало. Спасибо.
Ланс Робертс,
2
Спасибо, у меня тоже работает. TimeElapsed()дает результат в миллисекундах. Я не реализовал какую-либо компенсацию накладных расходов, потому что меня больше беспокоил эффект заикания в подсчете накладных расходов, чем безупречная точность.
Джастин
2
Это много подслушанного (в строках кода для управления) - если вы можете жить с точностью ~ 10 мс, ответ @Kodak ниже дает то же самое в одной строке кода (импорт GetTickCountиз kernel32).
BrainSlugs83 08
Как вы используете StartCounterAnd TimeElapsed? Я сделал экземпляр Timer CTimerв начале, и With StartCounterя просто написал .StartCounterпосле того, как моя подпрограмма началась, .TimeElapsedи мне ответили Invalid use of property. Когда я не говоря .StartCounterуже о том, он говорит мне, что объект не установлен.
Revolucion для Моники
Для excel 2010: Declare PtrSafe Function stackoverflow.com/questions/21611744/…
user3226167
48

Функция таймера в VBA дает вам количество секунд, прошедших с полуночи, с точностью до 1/100 секунды.

Dim t as single
t = Timer
'code
MsgBox Timer - t
dbb
источник
18
Это не сработает - вы не можете добиться большего разрешения, взяв такое среднее значение.
Эндрю Скагнелли
4
Тем не менее, если вы измеряете производительность в VBA, получить разрешение в 1/100 секунды - это неплохо. - Вызов одного вызова времени может занять пару мсек. Если вызов настолько быстр, что вам нужно такое большое разрешение, чтобы рассчитать время, вам, вероятно, не нужны данные о производительности этого вызова.
BrainSlugs83 08
1
примечания: на Mac таймер работает с точностью до одной секунды - и это может иметь отрицательные числа, если он начинается до полуночи и заканчивается после полуночи
TmTron,
32

Если вы пытаетесь вернуть время как секундомер, вы можете использовать следующий API, который возвращает время в миллисекундах с момента запуска системы:

Public Declare Function GetTickCount Lib "kernel32.dll" () As Long
Sub testTimer()
Dim t As Long
t = GetTickCount

For i = 1 To 1000000
a = a + 1
Next

MsgBox GetTickCount - t, , "Milliseconds"
End Sub

после http://www.pcreview.co.uk/forums/grab-time-milliseconds-included-vba-t994765.html (поскольку timeGetTime в winmm.dll у меня не работал, а QueryPerformanceCounter был слишком сложен для поставленной задачи)

Кодак
источник
Это отличный ответ. Обратите внимание: точность возвращаемых данных выражается в миллисекундах, однако счетчик имеет точность только примерно до 1/100
BrainSlugs83 08
хм, если разрешение здесь такое же, как у таймера, то я бы выбрал таймер
Kodak
Что это за Public Declare Function ...роль? Он создает ошибку при добавлении вашего кода внизу моего
Revolucion для Моники
Вам необходимо переместить это публичное объявление в верхнюю часть модуля
Kodak
3
Sub Macro1()
    Dim StartTime As Double
    StartTime = Timer

        ''''''''''''''''''''
            'Your Code'
        ''''''''''''''''''''
    MsgBox "RunTime : " & Format((Timer - StartTime) / 86400, "hh:mm:ss")
End Sub

Вывод:

Время выполнения: 00:00:02

Гаджендра Сантош
источник
2

Мы уже много лет использовали решение на основе timeGetTime в winmm.dll для точности до миллисекунд. См. Http://www.aboutvb.de/kom/artikel/komstopwatch.htm.

Статья на немецком языке, но код в загружаемом файле (класс VBA, оборачивающий вызов функции dll) достаточно прост для использования и понимания, не имея возможности прочитать статью.

Том Юргенс
источник
0

Секунды с двумя знаками после запятой:

Dim startTime As Single 'start timer
MsgBox ("run time: " & Format((Timer - startTime) / 1000000, "#,##0.00") & " seconds") 'end timer

формат секунд

Миллисекунды:

Dim startTime As Single 'start timer
MsgBox ("run time: " & Format((Timer - startTime), "#,##0.00") & " milliseconds") 'end timer

формат миллисекунд

Миллисекунды с разделителем запятой:

Dim startTime As Single 'start timer
MsgBox ("run time: " & Format((Timer - startTime) * 1000, "#,##0.00") & " milliseconds") 'end timer

Миллисекунды с разделителем запятой

Просто оставьте это здесь для всех, кто искал простой таймер, отформатированный с секундами до двух десятичных знаков, как и я. Я люблю использовать эти короткие и милые маленькие таймеры. Они занимают только одну строку кода в начале подпрограммы или функции и еще одну строку кода в конце. Они не должны быть безумно точными, меня обычно не волнует что-либо менее 1/100 секунды лично, но таймер миллисекунд даст вам наиболее точное время работы из этих 3. Я также читал вас может получить неправильные показания, если он сработает при переходе через полночь, что является редким случаем, но просто к сведению.

техноман23
источник
Полезно только первое, так как таймер имеет разрешение 10 мс.
Густав