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

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

Загадки Python - Генерация простых чисел!
Загадки Python - Генерация простых чисел!
Обычно существует несколько способов решения задач даже пограничной сложности. Как же определить оптимальное и эффективное решение?
96
0
135 888
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Если ваши функции не очень медленные, вам понадобится таймер с очень высоким разрешением. Самый точный из известных мне - QueryPerformanceCounter. Google для получения дополнительной информации. Попробуйте вставить следующее в класс, назовите его, скажем, CTimer, затем вы можете создать экземпляр где-нибудь в глобальном масштабе и просто вызвать .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

Я реализовал это в Excel VBA (добавив накладные расходы, как указано в этой статье базы знаний: support.microsoft.com/kb/172338. Это отлично сработало. Спасибо.

Lance Roberts 15.10.2008 02:55

Спасибо, у меня тоже работает. TimeElapsed() дает результат в миллисекундах. Я не реализовал какую-либо компенсацию накладных расходов, потому что меня больше беспокоил эффект заикания в подсчете накладных расходов, чем безупречная точность.

Justin 11.01.2011 18:59

Это много подслушанного (в строках кода для управления) - если вы можете жить с точностью ~ 10 мс, ответ @Kodak ниже дает то же самое в одной строке кода (импорт GetTickCount из kernel32).

BrainSlugs83 08.03.2014 04:45

Как вы используете StartCounter и TimeElapsed? Я сделал экземпляр таймера CTimer в начале и With StartCounter, я просто написал .StartCounter после того, как мой сабвуфер начал, и .TimeElapsed, и он ответил мне Invalid use of property. Когда я оставляю .StartCounter в покое, он сообщает мне, что объект не установлен.

Revolucion for Monica 27.04.2017 23:25

Для Excel 2010: Declare PtrSafe Functionstackoverflow.com/questions/21611744/…

user3226167 26.02.2019 04:45

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

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

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

Dim t as single
t = Timer
'code
MsgBox Timer - t

Это не сработает - вы не можете добиться большего разрешения, взяв такое среднее значение.

Andrew Scagnelli 04.06.2009 17:58

Тем не менее, если вы измеряете производительность в VBA, получить разрешение в 1/100 секунды - это неплохо. - Вызов одного вызова времени может занять пару мсек. Если вызов настолько быстр, что вам нужно такое большое разрешение, чтобы рассчитать его время, вам, вероятно, не нужны данные о производительности для этого вызова.

BrainSlugs83 08.03.2014 04:53

примечания: на Mac таймер работает с точностью до одной секунды - и может быть получено отрицательное число, если он начинается до полуночи и заканчивается после полуночи.

TmTron 04.08.2016 17:39

Если вы пытаетесь вернуть время как секундомер, вы можете использовать следующий 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 секунды (то есть, он может быть отключен на 10-16 мс) через MSDN: msdn.microsoft.com/en-us/library/windows/desktop/…

BrainSlugs83 08.03.2014 04:50

хм, если разрешение здесь такое же, как у таймера, то я бы пошел с таймером

Kodak 12.03.2016 17:46

Что такое Public Declare Function ...? Он создает ошибку при добавлении вашего кода внизу моего

Revolucion for Monica 27.04.2017 20:54

Вам нужно переместить это публичное объявление в верхнюю часть вашего модуля.

Kodak 28.04.2017 13:50

Для новичков эти ссылки объясняют, как выполнить автоматическое профилирование всех подписок, время которых вы хотите отслеживать:

http://www.nullskull.com/a/1602/profiling-and-optimizing-vba.aspx

http://sites.mcpher.com/share/Home/excelquirks/optimizationlink см. procProfiler.zip в http://sites.mcpher.com/share/Home/excelquirks/downlable-items

Sub Macro1()
    Dim StartTime As Double
    StartTime = Timer

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

Выход:

RunTime : 00:00:02

Секунды с двумя десятичными пробелами:

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

seconds format

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

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

milliseconds format

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

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

Milliseconds with comma seperator

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

Полезен только первый, так как таймер имеет разрешение 10 мс.

Gustav 03.09.2020 10:37

Другие вопросы по теме