2012-09-12 108 views
14

我一直在玩圍繞測量代碼執行時間來衡量在本地和我的服務器上執行我的腳本之間的差異。有一次,我忘記禁用screen updating,並感謝我對閃光燈不敏感,然後才更詳細地考慮它:屏幕更新的影響

當我第一次開始使用VBA時,我總是認爲它只是用來使它沒有讓最終用戶認爲自己的電腦即將崩潰。當我開始更多地閱讀提高代碼效率的知識時,我明白了它的作用,但screen updating確實對代碼執行時間有多大影響?

+4

根據你的代碼在做什麼,將Application.Calculation設置爲「手動」通常也會給你一個很大的提速。您通常會爲長時間運行的宏執行這兩個操作。不要忘記重置計算 - 這是一個持久的設置。 –

+1

Aslo,在運行Screenupdating關閉的情況下,您可以通過Application.Statusbar ='讓用戶知道進度。然後設置爲「False」將其恢復正常。有些人需要看到進步,否則他們認爲他們的計算機已經凍結並且迫使所有人關閉。 – Rory

+0

我也讀過Excel中的默認數據格式實際上是貨幣,所以最好在貨幣可以用作數據值而不是Double時儘可能避免數據轉換。 –

回答

23

如果代碼與Excel交互的方式導致屏幕內容發生更改,關閉屏幕更新只會影響執行時間。屏幕變化越大,影響就越大。其他發佈的答案恰當地證明了這一點。

其他可以影響執行時間的應用程序設置是計算和事件處理。使用此代碼模板爲起點(錯誤處理機制確保這些特性在子結束重新打開,即使錯誤)

Sub YourSub() 
    On Error GoTo EH 

    Application.ScreenUpdating = False 
    Application.Calculation = xlCalculationManual 
    Application.EnableEvents = False 

    ' Code here 

CleanUp: 
    On Error Resume Next 
    Application.ScreenUpdating = True 
    Application.Calculation = xlCalculationAutomatic 
    Application.EnableEvents = True 
Exit Sub 
EH: 
    ' Do error handling 
    GoTo CleanUp 
End Sub 

其他技術存在,可以提供執行更大的提升速度。

最有用的包括

  1. 避免SelectActivateActiveCell/Sheet/Workbook儘可能。相反,聲明和分配變量並引用它們。
  2. 引用大範圍時,將範圍數據複製到變體數組進行處理,並將結果複製回到之後的範圍。
  3. 使用Range.SpecialCells,Range.FindRange.AutoFilter來限制引用的單元格的數量。

有很多關於這些技術的例子。

+1

你希望你的'CleanUp:'做與它目前相反的事情對? ;) – enderland

+0

@enderland哎呀... –

2

首先,我一直在使用由裏奇(UK)發帖#腳本7 Here

它只是通過一個循環,一個小區改變i的值進行迭代。我已經稍微改變了它,所以它循環了10,000次,並且我對樣本大小執行了10次。

屏幕更新對我的代碼執行速度有什麼影響?

這些都是執行的長度時Screen Updating被禁用和啓用:

Disabled Enabled 
0.61909653 2.105066913 
0.619555829 2.106865363 
0.620805767 2.106866315 
0.625528325 2.102403315 
0.625319976 2.0991179 
0.621287448 2.105103142 
0.621540236 2.101392665 
0.624537531 2.106866716 
0.620401789 2.109004449 

正如你可以看到它需要近3.5倍,只要當Screen Updating未禁用執行代碼。

這兩個代碼都使用VB編輯器中的運行按鈕,而不是'看'電子表格。

2簡單的線條在你的代碼的開始和結束:

Application.ScreenUpdating = False 
Application.ScreenUpdating = True 

但是,他們可以對你的執行效率有很大的影響!

說明:顯然Screen Updating的優點在很多人都知道,但這可能對初學者有好處,我覺得查看數字很有趣!

6

如果您想查看ScreenUpdating爲什麼ScreenUpdating很重要的一個相當激烈的例子,請運行以下代碼。在Excel 2011中,我需要大約45倍的時間才能在沒有ScreenUpdating = false的情況下運行此交換!這是一個龐大的時間差異。

Sub testScreenUpdating() 

    Dim i As Integer 
    Dim numbSwitches As Integer 
    Dim results As String 

    'swap between sheets this number of times 
    numbSwitches = 1000 

    'keep track of time 
    Dim startTime As Double 
    startTime = Time 

    'swap between sheets 1/2 (need both sheets or this will crash) 
    For i = 1 To numbSwitches 
     Sheets(1 + (i Mod 2)).Select 
    Next i 

    'get results 
    results = "Screen Updating not disabled: " & Format(Time - startTime, "hh:mm:ss") & " seconds" 
    startTime = Time 

    'scenario 2 - screenupdating disabled 

    Application.ScreenUpdating = False 

    'swap between sheets 1/2 (need both sheets or this will crash) 
    For i = 1 To numbSwitches 
     Sheets(1 + (i Mod 2)).Select 
    Next i 

    Application.ScreenUpdating = True 

    'get results for part two 
    results = results & vbCrLf & "Screen Updating IS disabled: " & Format(Time - startTime, "hh:mm:ss") & " seconds" 

    'show results 
    MsgBox results 


End Sub 

而且,雖然我們對方式,提高辦事效率的話題,另一個關鍵點是SelectSelectionActivate很少(如果有的話)必要的。當你錄製宏時,它總是會使用這些宏,但是當你需要在代碼中實際使用它們時,很少有這種情況。同樣,標題中的Active(例如ActiveCell)通常表示您的代碼會較慢,因爲您可能正在選擇單元格。

您幾乎總是可以專門引用單元格/工作表並避免選擇。例如:

msgbox (Worksheets(1).Range("A1").value) 

無論您目前是否在第一張工作表上都能正常工作。一個常見的新VBA錯誤是做更類似的事情:

Worksheets(1).Select 
msgbox (Range("A1").value) 

這是一個不必要的步驟。

這增加了代碼運行時間的重要時間。

+0

說得好。 Alistair,如果你想了解如何避免選擇的一些很好的例子,請參閱Chris Nielsen的回答:http://stackoverflow.com/a/10717999/138938 –

0

有一個重要的事情要了解屏幕更新,我沒有看到任何以前的答案。從我自己的測試中,我發現關閉屏幕更新大約需要15ms(通過Excel Interop在C#中進行測試)。請記住,如果你會執行任何需要更少時間的事情。畢竟在某些循環中不要多次打開/關閉屏幕更新。那將是真正的性能殺手。

還有一個注意事項(你可能不想聽到),如果你想快速使用C++。它通常比VBA快5到10倍(不要理解我的實際情況取決於你的實際情況)。

0

我知道這是一個古老的線程,但:

1)不要設置ScreenUpdating =真實的,但reme​​ber並設置回它原來的值。 2)更改工作簿也會重置Screenupdating。