Як ви перевіряєте час роботи коду VBA?


Відповіді:


81

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

2
Я реалізував це в Excel VBA (додавши в "Накладні витрати", як згадується в цій статті KB: support.microsoft.com/kb/172338 . Це чудово працювало. Дякую.
Ленс Робертс,

2
Дякую, це добре працює і для мене. TimeElapsed()дає результат у мілісекундах. Я не застосував жодної компенсації накладних витрат, оскільки мене більше турбував ефект заїкання при розрахунку накладних витрат, ніж ідеальна точність.
Джастін

2
Це багато підслуханого (у рядках коду для управління) - якщо ви можете жити з точністю ~ 10 мс, відповідь @ Kodak нижче дає те саме в одному рядку коду (імпортування GetTickCountз kernel32).
BrainSlugs83,

Як ви використовуєте StartCounterІ TimeElapsed? Я зробив екземпляр Timer CTimerна початку, і With StartCounterя просто написав .StartCounterпісля того, як моя підручна програма почала, .TimeElapsedі це мені відповіло Invalid use of property. Коли я не .StartCounterкажучи вже, це говорить мені, що об'єкт не встановлений.
Революція для Моніки

Для Excel 2010: Declare PtrSafe Function stackoverflow.com/questions/21611744 / ...
user3226167

48

Функція таймера у VBA дає вам кількість секунд, що минули з півночі, до 1/100 секунди.

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

18
Це не буде працювати - ви не можете отримати більше дозволу, якщо взяти середнє значення таким чином.
Ендрю Скагнеллі,

3
Тим не менше, якщо ви вимірюєте продуктивність у VBA, отримати 1/100 секунди роздільної здатності непогано. - Виклик синхронізації дзвінків сам по собі може зайняти пару мс. Якщо дзвінок настільки швидкий, що вам потрібна така велика роздільна здатність, щоб визначити час, вам, ймовірно, не потрібні дані про ефективність цього дзвінка.
BrainSlugs83,

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

хм, якщо роздільна здатність тут така ж, як і з таймером, я б пішов з таймером
Kodak

Яка Public Declare Function ...частина? Це створює помилку під час додавання вашого коду внизу мого
Revolucion for Monica

Вам потрібно перемістити цю публічну декларацію у верхню частину вашого модуля
Kodak,

4

Для новачків за цими посиланнями пояснюється, як зробити автоматичне профілювання всіх підводних пристроїв, за якими ви хочете стежити за часом:

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


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) досить простий у використанні та розумінні, не маючи можливості прочитати статтю.


1

Секунди з 2 десятковими пробілами:

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

Мілісекунди з розділювачем комами

Просто залишаю це тут для тих, хто шукав простий таймер, відформатований із секундами до 2 знаків після коми, як я. Це короткі та солодкі маленькі таймери, якими я люблю користуватися. Вони займають лише один рядок коду на початку підпрограми або функції і один рядок коду знову в кінці. Вони не призначені для божевільних точних, мені, як правило, байдуже ні про що менше 1/100 секунди особисто, але таймер мілісекунд дасть вам найбільш точний час роботи з цих 3. Я також вас прочитав може отримати неправильне зчитування, якщо трапляється, що він працює під час перетину опівночі, рідкісний приклад, але просто FYI.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.