Оптимизиране на VBA макроси
Бележки от първо лице за ИТ, новини и технологична старост.
Блог → Оптимизиране на VBA макроси. Част 1
Така че да започваме! И нека започнем, както обикновено, с общи принципи. Първо, дори и да звучи богохулно за програмното братство - не оптимизирайте кода за скорост, когато не е необходимо. Такава оптимизация обикновено е загуба на време! Опитайте се преди всичко да намерите места, които забавят изпълнението на цялата програма. По правило това са няколко (10-20%) неправилно избрани инструкции и ако бъдат открити и коригирани, производителността ще се увеличи с 80-90% (т.нар. "правило 20/80", което важи не само за програмирането, но и за много други индустрии).
Също така не трябва да мислите, че пренасянето на кода на C++ или друг език ще ускори значително програмата. Ако алгоритъмът ви се провали или внедряването му е погрешно, няма да се подобри, ако го пренапишете на друг език. Ще кажа повече - една добре изградена VBA програма може да работи много по-бързо от креативността на лош C програмист. Но остава един важен въпрос: къде да търсим тези „тесни места“. По-долу ще намерите някои общи съвети.
Започнете теста с повтарящи се цикли. Според моите експериментални данни IIf е три пъти по-малко ефективен от обикновения If: 44 секунди срещу 9 секунди с десет милиона изпълнения на процесор Pentium 166 (да, беше много отдавна, но същността на това не се променя). Какво означава това за нас? Само фактът, че на P166 IIf работи 4,4 милионни от секундата, а If е една милионна.
Възниква въпросът - колко важна е тази разлика? Не особено ако IIf е написано няколко пъти извън цикъла. И много важно, ако една неефективна операция се повтаря 10 милиона пъти в цикъл: времевата разликаизпълнение за 35 секунди е доста значително! Следователно изборът на изрази извън цикъла е по-малко важен от повтарящите се, „критични за времето“ цикли, както често се наричат. Очевидно е, че тук трябва да работите върху оптимизацията - това веднага ще даде осезаемо увеличение на скоростта на изпълнение.
Как да използвате интерфейси. Използвайте интерфейсите, предоставени от VBA в този ред: вградени функции, библиотеки с обекти на приложения, Win32 API, сложни алгоритми, внедрени във VBA (като алгоритъм за компресиране или анализатор на низов израз) и накрая компоненти на трети страни. Вградените функции работят най-бързо, функциите и методите на обектните библиотеки работят малко по-бавно. Е, техните собствени или взети от специализирани сайтове и от книги, внедряването на алгоритми във VBA обикновено работи най-бавно. Те обаче са за предпочитане пред "бързата и мръсна" техника с помощта на ActiveX, когато програмистът се опитва да "изгради" работеща програма за една нощ с помощта на голям брой обемисти чужди компоненти.
Защо така, ще попитате? ActiveX трябва да бъде регистриран в системния регистър. Трябва да създадете инсталатор и деинсталатор, да използвате RegSrv32, докато обикновено макросите за Word и Excel се разпространяват в архив. Неправилното деинсталиране на ActiveX или липсата му причинява грешки в регистъра и съответно широкото използване на ActiveX в бъдеще води до замърсяване на регистъра. Понякога ActiveX изискват допълнителни VB, C++ и т.н. изпълнения (в зависимост от това в какво са написани). Ако ActiveX не изисква библиотеки за изпълнение, те почти винаги заемат доста място, тъй като тези библиотеки (VCL, MFC) вече се съдържат в .ocx файла. В същото време много ActiveX с размер двеста килобайта могат лесно да бъдат замененипрост код, който отнема по-малко от десет килобайта и който освен това може да бъде променян, коригиран и пренаправен, за да отговаря на вашите нужди, както желаете.
Друг проблем с ActiveX е, че те обикновено идват без изходен код. Ако има грешки в кода на компонента, които причиняват срив на програмата ви, не можете да ги коригирате. Особено не препоръчвам да използвате компоненти за декорация, "свирки и камбани", добавяйки всякакви нестандартни контроли и други боклуци. Това води до сериозни загуби в скоростта на програмата и всеки нестандартен интерфейс може да бъде създаден с помощта на вградени контроли. Ще се опитам да обясня казаното с примери.
Пример 1. Сортирането в Word се извършва най-добре не чрез използване на различните алгоритми, предлагани от VB сайтове и книги (и със сигурност не чрез използване на метода на мехурчето), а чрез извикване на метода Word-Basic.SortArray. За масиви в Excel обикновено трябва да използвате своя собствена процедура, която реализира блоково сортиране, бързо сортиране или групово сортиране. Когато сортирате клетки на Excel или параграфи на Word, използвайте метода Selection.Sort, специално създаден за тази цел.
Пример 2. Необходимо е да се изчисли стойността на аритметичен израз, съдържащ се в низ. Например, "12+12*(5-2)" в крайна сметка трябва да стане 48. Тук се препоръчва да използвате (в низходящ ред на предпочитанията): • Application.Evaluate метода на Excel, Eval на Access или малко известната вградена в Word команда Calculate Value (Selection.Calculate, WordBasic.ToolsCalculate); • анализатор на низови изрази, написан на VBA - бавен, но сигурен начин; Готовият код може да бъде намерен на някои VB сайтове и в VB Source Book; • Метод Eval() от WindowsХост за скриптове (отхвърлен като недостъпен от Windows 95, но ако производителността е критична, използвайте го вместо анализатор на VBA).
Добро решение е да направите това чрез Selection.Calculate (ние създаваме документ и отпечатваме израз в него, който след това може да бъде изчислен):
Документи. Добавяне със селекция
.TypeText "12 + 12 * (5 - 2)" .HomeKey wdStory, wdExtend MsgBox .Calculate .Delete
Край с ActiveDocument.Close False
Командата WordBasic ToolsCalculate ви позволява да правите същото още по-лесно и по-бързо, тъй като можете да посочите низов израз като неин параметър:
Пример 3. Да предположим, че искаме да възпроизведем MP3 файлове от VBA. Как да го направим? Можете или да инсталирате MP3 кодека в системата (и той не е наличен по подразбиране дори в Windows XP) и да извикате MCI чрез Win32 API, или да използвате ActiveX компоненти на трети страни, които внедряват кодеци (това е случаят, когато наистина са необходими). Друг вариант е да използвате кодек с отворен код като Lame, пакетиран като външен DLL.
Const C = 10000 x! = Таймер За i& = 1 до C ' Изпълнение на действие 1 Следващо i x = Таймер - x
y! = Таймер За i& = 1 до С ' Изпълнение на действие 2 Напред i y = Таймер - y
MsgBox "x=" & x & vbCrLf & "y=" & y & vbCrLf & _ "x/y=" & x/y & vbCrLf & "y/x=" & г/х
Следете освобождаването на ресурси. Ако работите с големи количества данни, стартирайте помощна програма, която предоставя подробна информация за свободната памет (като FreeMemory или MemGlance), за да определите дали вашата програма „забравя“ да освободи ресурси, след като са били използвани. Типични симптоми: неуспехоткрийте грешки в алгоритъма, но въпреки това програмата работи бавно и при многократни стартирания времето за работа се увеличава (това е може би най-тревожният симптом, който почти напълно показва улавянето на ресурси без последващо освобождаване). Сравнете колко памет, обемно пространство, ресурси на GDI и ресурси на потребителски модул заема дадено приложение преди и след бавна работа.