Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.77/113: Рейтинг темы: голосов - 113, средняя оценка - 4.77
Эксперт WindowsАвтор FAQ
17996 / 7697 / 892
Регистрация: 25.12.2011
Сообщений: 11,470
Записей в блоге: 16
1

[Статья] Как заставить Вашу программу на VB работать быстрее?

08.01.2015, 17:13. Показов 21727. Ответов 25
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Автор: Рут Глушкин, VBStreets

Прежде всего заставьте программу работать, а затем беспокойтесь о ее быстродействии.

Существует множество способов ускорения вашей VB программы. К сожалению, большинство из них не приводят к особо впечатляющим результатам. Даже если ваша программа работает с огромными коллекциями, преобразование их в массивы, возможно, спасет вам какой-то процент или два в процессе выполнения программы. С другой стороны, переписывание основных алгоритмов программы может сократить процесс выполнения в сотни раз.

Ниже приводятся несколько способов, с помощью которых вы можете намного улучшить эффективность вашей программы.

1. Производя арифметические операции, оперируйте целыми числами и используйте целочисленные операторы, где это возможно. Используйте оператор "\" - целочисленного деления вместо "/" - деления с плавающей точкой. Используйте "* .5" вместо "/ 2", поскольку команда ассемблера "MUL" быстрее, чем "FDIV".

2. Где только это возможно, не применяйте квадратные корни, например:

Visual Basic
If a * a + b * b = 4 Then ...
гораздо быстрее, чем
Visual Basic
If Sqr(a * a + b * b) = 2 Then ...
3. Если Вам необходимо производить повторяющиеся вычисления как можно быстрее, наиболее эффективно создать таблицу значений функции, и просто заменять исходные данные на соответствующие результаты из этой таблицы. Например, если заранее указать в таблице x и y как координаты каждой точки на окружности на расстоянии 1-2 градуса, это будет достаточно точно и гораздо быстрее, чем вычислять их значения, используя функции SIN, COS и TAN.

4. Перепишите вашу программу на C++ или Delphi. (Это, конечно, не всегда возможно, но это - единственное решение, когда несмотря ни на что, ваша программа работает невыносимо медленно).

5. Установите у себя 5 или 6 версию VB. Программы, откомпилированные в VB с опцией Native, конечно, работают медленнее, чем программы, написанные на C++ или Delphi, но они намного быстрее, чем неоткомпилированные программы, создаваемые более ранними версиями VB.

6. Создавайте шаблоны. Пользуйтесь средствами контроля производительности для того, чтобы определить, где именно ваша программа проводит больше всего времени. Эти средства встроены в VB 4 и 5, и VB 6 Enterprise Edition. Не теряйте времени по улучшению того кода, который и так достаточно быстрый.

7. Распаковывайте графику. Всегда пользуйтесь файлами с расширением .bmp, а не запакованными .jpg или .gif файлами. Эти файлы хранятся в программе в запакованном виде, и требуется дополнительное время для их раскрытия.

8. Используйте Set your_form = Nothing, когда данная форма вам больше не нужна. Это экономит память и может сэкономить массу времени, когда у вас много форм, которые вы должны хранить в памяти. Если же у вас немного форм, гораздо эффективнее загружать их все в начале программы. Затем они будут появляться на экране быстрее, когда они вам понадобятся. Не закрывайте их до конца, вместо этого применяйте методы Hide/Show по мере необходимости.

9. Используйте массивы вместо коллекций. Массивы намного быстрее. Используйте коллекции только тогда, когда вам нужны их особые свойства, например, просмотр по ключу. Заранее определяйте массивы максимально возможного размера, чтобы не пришлось динамически выделять под них память в процессе выполнения программы - ReDim.

10. Если вам нужно обнулить все элементы динамического массива, используйте ReDim. Это займет больше времени, чем оставить массив в покое, но это гораздо быстрее, чем обнуление элементов массива в цикле.

11. Если вам нужно обнулить все элементы массива фиксированной длины, объявленного с применением Dim, используйте Erase. Это уничтожит динамический массив, но обнулит массив фиксированной длины.

12. Пользуйтесь функциями API MemCopy или RtlMoveMemory для копирования массивов вместо копирования их элементов в цикле.

13. Всегда указывайте определенные типы данных вместо Variant. Всегда объявляйте переменную вместе с ее типом. Если вы не укажете тип переменных, она по умолчанию будет Variant.

14. Всегда указывайте определенные типы объектов вместо объявления переменной типа Object. Будьте настолько точны, насколько это возможно.

Например,

Object - плохо
Control - лучше
TextBox - лучше всего.

15. Никогда не очищайте коллекцию, удаляя ее элементы. Уничтожайте их, используя Set элемент = Nothing.

16. Объявляйте объект и выделяйте под него память на отдельных строках кода. Строка "Dim obj As New MyClass" выполняется медленнее, чем две отдельных строки "Dim obj As MyClass" "Set obj = New MyClass".

17. Для проверки строки нулевой длины "" используйте функцию Len. То есть:

Visual Basic
If Len(my_string) = 0 Then ... гораздо быстрее, чем:
If my_string = "" Then
18. Используйте With для длинных последовательностей указаний свойств объектов, повторяемых несколько раз. Это выполняется быстрее, чем если вы повторите серии объектов в каждой отдельной команде.

19. Применяйте как можно меньше операций с переменными типа String, эти операции медленные.

20. Упорядочивайте команды внутри Select Case таким образом, чтобы наиболее часто встречающиеся значения были вначале.

21. Ощущаемое быстродействие гораздо важнее фактического. Представьте себе, что вы нажали на кнопку, и в течение 10 секунд ничего не происходит. Эти 10 секунд покажутся вам часом. Добавьте ProgressBar, и тогда пользователь даже не заметит, что прошло 10 секунд.

22. Когда у вас в программе множество динамически меняющихся картинок, поместите их все в невидимые Images на первую загружаемую форму, а затем загружайте их по мере необходимости. Никогда не работайте с файлами. Строка

Visual Basic
Form2.Image1.Picture = LoadPicture("yourfile.bmp")
выполняется в десятки раз медленнее, чем
Visual Basic
Form2.Image1.Picture = Form1.Image1.Picture
23. Если вам нужно производить множество операций с файлами или с переменными типа String, всегда добавляйте знак $ после имени команды, например, Mid$ вместо Mid, потому что Mid работает с параметрами типа Variant, в то время, как Mid$ работает с параметрами типа String, что в 3 раза быстрее.

24. Чтобы создать ощущение, что ваша программа выполняется быстро, показывайте первую форму как можно быстрее. Вставьте команду Show в процедуру Form1_Load(), чтобы она появилась на экране до окончания выполнения долгих начальных настроек и вычислений. Помещайте в процедуру каждой формы Load как можно меньше кода для того, чтобы она появлялась как можно быстрее. Если требуется много времени для загрузки начальной формы, создайте дополнительную форму с ProgressBar и загружайте ее немедленно. Эта форма должна быть на экране все время выполнения начальных настроек, она убирается с экрана в конце процедуры Form1_Load().

25. Распределяйте функции и процедуры по модулям. Когда одна процедура вызывает другую, загружается весь модуль второй процедуры. Если одна процедура вызывает несколько процедур из разных модулей, все эти модули загружаются в память. Если же все процедуры находятся в одном модуле, они все загружаются одновременно.

26. Не тратьте память бездумно. Иногда вы можете заставить вашу программу выполняться быстрее, используя больше памяти, но иногда применение большей памяти сильно замедляет вашу программу. В частности, если вы используете так много памяти, что ваша программа требует больше оперативной памяти, чем есть в системе, система будет загружать программу постранично, что сильно замедлит ее выполнение.

27. Для сокращения требуемой оперативной памяти присваивайте Form1.AutoRedraw = False.

Но для ускорения сложных графических операций присваивайте Form1.AutoRedraw = True.

28. Присваивайте Object.ClipControls = False, где это возможно (прочтите Help для более подробной информации).

29. Для изменения местоположения контролек используйте команду Move вместо изменений значений Left и Top.

30. Если вам нужно изменить серию свойств, связанных с внешним видом (Appearance) объекта, вначале сделайте его невидимым, и только по завершении всех операций, сделайте его снова видимым.

31. Кэшируйте свойства, которые вы применяете много раз. Например, если ваша программа несколько раз обращается к свойству txtLastName.Left, поместите это значение в переменную, и работайте с ней. Обращение к переменной намного быстрее, чем к свойствам объекта.

32. Для того, чтобы нарисовать прямоугольник, вместо четырех команд Line, используйте:
Visual Basic
Line (x1, y1)-(x2, y2), , B
33. Вместо PictureBoxes применяйте, где это возможно, Images, поскольку Image требует гораздо меньше памяти.

34. Используйте Frames для хранения других объектов вместо PictureBoxes, так как Frame требует меньше памяти.

35. Неважные объекты помещайте в массивы. Например, множество форм содержат множество Labels. Поместите их все в один массив. Массив, содержащий 10 объектов, требует меньше памяти, чем 10 отдельных объектов.

36. Выполняйте длинные вычисления на фоне выполнения других операций, используя Timer.

37. Используйте комментарии и значимые имена переменных. Длинные комментарии и имена переменных, а также пустые строки не увеличивают размера вашей программы, так что нет никакого вреда в их применении.

38. Не нумеруйте каждую строку вашего кода, поскольку нумерация строк увеличивает размер вашей программы.

39. Убирайте неиспользуемые переменные и участки кода, так как они остаются в программе, и увеличивают как ее размер, так и выделяемую под нее оперативную память.

40. Используйте DoEvents, чтобы позволить пользователю выполнять другие операции, пока ваша программа выполняет какой-то длительный процесс. Это уменьшит недовольство пользователя даже, если это не заставит вашу программу выполняться быстрее.

41. Используйте функции API FindFirstFile, FindNextFile, и FindClose для быстрого поиска файлов и папок. Но помните, что не всегда обращение к функциям API быстрее. Это всегда сложнее, и иногда весьма рискованно, чем применение стандартных функций VB.

42. Функции UCase$ и LCase$ позволяют вам осушествлять сравнения вне зависимости от регистра текста, но нижеследующие функции API гораздо быстрее:

Visual Basic
Declare Function CharLower Lib "user32" _
Alias "CharLowerA" (ByVal lpsz As String) As String
 
Declare Function CharUpper Lib "user32" _
Alias "CharUpperA" (ByVal lpsz As String) As String
43. Используйте временные переменные для многократного обращения к сложным выражениям. Например, вам нужно присвоить различные значения объекту
SelectedEmployee.NextOfKin.HomeInformation.Address. Вместо того, чтобы обращаться к этому длинному выражению несколько раз, используйте:

Visual Basic
Dim addr As AddressInfo
Set addr = SelectedEmployee.NextOfKin.HomeInformation.Address
addr.Street = txtStreet.Text
addr.City = txtCity.Text
addr.State = txtState.Text
addr.Phone = txtPhone.Text
Команда With дает такое же ускорение, поэтому вы можете использовать:
Visual Basic
With SelectedEmployee.NextOfKin.HomeInformation.Address
.Street = txtStreet.Text
.City = txtCity.Text
.State = txtState.Text
.Phone = txtPhone.Text
End With
44. При вызове процедуры или функции, где это возможно, передавайте параметры ByRef, а не ByVal. Когда вы используете ByRef, программа передает только небольшой адрес переменной. Когда же вы используете ByVal, программа должна создать новую копию передаваемой переменной. Обычно гораздо быстрее передать адрес, чем создать копию переменной. Однако, когда вы формируете вызов функций, относящихся к разным процессам, ByVal выполняется быстрее. При таком вызове, VB должен в любом случае запаковать значение переменной для передачи ее другому процессу. Если вы используете ByRef, VB должен затем распаковать результат, и это отнимает больше времени.

45. Для вычисления степеней используйте оператор "*" вместо "^".

Например, A = B * B быстрее, чем A = B ^ 2.

46. Если вам нужно сформировать длинную строку, формируйте ее по частям, и затем собира йте все части воедино. Например, у вас есть процедуры AddText1, AddText2, и т.д., которые добавляют текст к переменной типа String.

Тогда этот код:

Visual Basic
Dim txt As String
txt = AddText1(txt)
txt = AddText2(txt)
txt = AddText3(txt)
будет выполняться медленнее, чем следующий:
Visual Basic
Dim txt As String
Dim txt1 As String
Dim txt2 As String
Dim txt3 As String
AddText1(txt1)
AddText2(txt2)
AddText3(txt3)
txt = txt1 & txt2 & txt3
В первом примере, процедуры AddText должны манипулировать длинными строками. Во втором примере они работают с относительно короткими строками.

47. Запоминайте промежуточные результаты математических вычислений.

Например, этот код:
Visual Basic
Xsquare = x * x
Ysquare = y * y
a = 2 * Xsquare + 3 * Ysquare
b = 3 * Xsquare + 5 * Ysquare
If a + b > 50 Then ...
выполняется быстрее, чем следующий:
Visual Basic
If 2 * x * x + 3 * y * y + _
3 * x * x + 5 * y * y > 50 _
Then ...
48. Не вставляйте в цикл проверку со значением, возвращаемым функцией.

Например, этот код:
Visual Basic
i = 1
Do While i
выполняется значительно медленнее, чем этот:
Visual Basic
i_max = SlowFunction()
i = 1
Do While i
Примечание: цикл For не пересчитывает свои границы каждый раз. Когда цикл For начинается, система определяет граничные значения и запоминает их. Она не будет пересчитывать их каждый виток цикла. Следовательно, нижеследующий код выполняется достаточно быстро:
Visual Basic
For i = 1 To SlowFunction()
total = total + i
Next i
8
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
08.01.2015, 17:13
Ответы с готовыми решениями:

Как заставить функцию работать быстрее?
Может кто подсказать в плане оптимизации как заставить функцию Check() работать быстрее? Применил...

Оцените, будьте так любезны! Как заставить игры работать чуточку быстрее на таком компьютере?
---------------------------------- 01 - Операционная система ---------------------------------- ...

Можно ли заставить ЖД работать быстрее?
Подключил я внешний хард ко второму пню, чтобы перегнать туда инфу с компа, но появилась надпись...

Как заставить программу работать с консолью?
Как сделать что бы моя прога работала с консолью(то есть могла посылать запросы в консоль и читать...

25
Модератор
Эксперт функциональных языков программированияЭксперт Python
36606 / 20334 / 4221
Регистрация: 12.02.2012
Сообщений: 33,653
Записей в блоге: 13
08.01.2015, 17:40 2
Нда... Хотел сам такую статью написать, но "заболтал"...

Что же касается приведенных выше советов, то некоторые из них вполне тривиальны (особенно прикольно выглядит совет №4). Есть и небесспорные (например, нумеруя строки как в старых версиях Бэйсика, вы получаете возможность в обработчике ошибок использовать функцию ERL - номер ошибочной строки).

Ну, и есть, что добавить.

49. Не используйте variant-переменные, как параметры циклов. Вообще быстрее всего использовать для параметров циклов тип long (совет для новичков);

50. Если алгоритм требует наращивания строки, велик соблазн написать так:

Visual Basic
1
      A$=A$+s$
но гораздо быстрее будет создать большой буфер A$ и помещать в него символы, используя mid$:

Visual Basic
1
     mid$(A,i%,1)=s$ : i%=i%+1
51. Избегайте использовать GoSub (устаревшая, но поддерживаемая возможность). Вызов GoSub выполняется значительно медленнее, чем вызов процедуры или функции;

52. Правило "бутылочного горлышка" - основное "торможение" любой программы вызывает одно-два узких места. Из нужно найти и ускорить. Оптимизировать остальной код большого смысла не имеет.

53. Чистка циклов

Visual Basic
1
2
3
   For i%=1 to 1000
        X(i%)=A*B(j%+5*k%)
   Next i%
Рациональнее вынести за пределы цикла вычисление индексного выражения, не зависящего от параметра цикла:


Visual Basic
1
2
3
4
   BB=B(j%+5*k%)
   For i%=1 to 1000
        X(i%)=A*BB
   Next i%
Выигрыш будет тем больше, чем больше витков выполняет цикл и чем сложнее индексное выражение.
5
6804 / 2831 / 527
Регистрация: 24.04.2011
Сообщений: 5,308
Записей в блоге: 10
09.01.2015, 08:15 3
Как ни странно, но нет одного действенного совета, который реально увеличивает скорость работы скомпилированной программы - настройка компилятора! Если убрать все лишние проверки в отлаженной программе, то она работает гораздо шустрее
[Статья] Как заставить Вашу программу на VB работать быстрее?
4
Модератор
9725 / 3686 / 871
Регистрация: 22.02.2013
Сообщений: 5,531
Записей в блоге: 78
11.01.2015, 13:43 4
Цитата Сообщение от Dragokas Посмотреть сообщение
5. Установите у себя 5 или 6 версию VB. Программы, откомпилированные в VB с опцией Native, конечно, работают медленнее, чем программы, написанные на C++ или Delphi, но они намного быстрее, чем неоткомпилированные программы, создаваемые более ранними версиями VB.
Это неверно.
Цитата Сообщение от Dragokas Посмотреть сообщение
Распаковывайте графику. Всегда пользуйтесь файлами с расширением .bmp, а не запакованными .jpg или .gif файлами. Эти файлы хранятся в программе в запакованном виде, и требуется дополнительное время для их раскрытия.
Это было актуально может в 98 году, но сейчас уже нет. При использовании bmp размер файла будет расти очень сильно.
Цитата Сообщение от Dragokas Посмотреть сообщение
Используйте Set your_form = Nothing, когда данная форма вам больше не нужна. Это экономит память и может сэкономить массу времени, когда у вас много форм, которые вы должны хранить в памяти.
Для выгрузки формы целесообразнее использовать Unload.
Цитата Сообщение от Dragokas Посмотреть сообщение
Заранее определяйте массивы максимально возможного размера, чтобы не пришлось динамически выделять под них память в процессе выполнения программы - ReDim.
Мой совет - выделять память порциями по 100 - 10000 элементов в зависимости от задачи.
Цитата Сообщение от Dragokas Посмотреть сообщение
Если вам нужно обнулить все элементы динамического массива, используйте ReDim. Это займет больше времени, чем оставить массив в покое, но это гораздо быстрее, чем обнуление элементов массива в цикле.
Цитата Сообщение от Dragokas Посмотреть сообщение
Если вам нужно обнулить все элементы массива фиксированной длины, объявленного с применением Dim, используйте Erase. Это уничтожит динамический массив, но обнулит массив фиксированной длины.
Еще быстрей будет RtlZeroMemory.
Цитата Сообщение от Dragokas Посмотреть сообщение
Пользуйтесь функциями API MemCopy или RtlMoveMemory для копирования массивов вместо копирования их элементов в цикле.
Это плохой совет, т.к. в массивах может быть что угодно и строки и объекты и структуры со строками и объектами, массивами.
Цитата Сообщение от Dragokas Посмотреть сообщение
Всегда указывайте определенные типы объектов вместо объявления переменной типа Object. Будьте настолько точны, насколько это возможно.
Для таких целей обычно придумывается интерфейс, вместо медленного IDispatch (Object).
Цитата Сообщение от Dragokas Посмотреть сообщение
Объявляйте объект и выделяйте под него память на отдельных строках кода. Строка "Dim obj As New MyClass" выполняется медленнее, чем две отдельных строки "Dim obj As MyClass" "Set obj = New MyClass".
Также добавлю что это не одно и тоже как многие думают.
Цитата Сообщение от Dragokas Посмотреть сообщение
Используйте With для длинных последовательностей указаний свойств объектов, повторяемых несколько раз. Это выполняется быстрее, чем если вы повторите серии объектов в каждой отдельной команде.
Неправда, разницы в скорости нет.
Цитата Сообщение от Dragokas Посмотреть сообщение
Когда у вас в программе множество динамически меняющихся картинок, поместите их все в невидимые Images на первую загружаемую форму, а затем загружайте их по мере необходимости. Никогда не работайте с файлами.
Тогда уж загружать предварительно в массив StdPicture'ов, это будет еще быстрее. А читать можно к примеру из PropertyBag'а.
Цитата Сообщение от Dragokas Посмотреть сообщение
Распределяйте функции и процедуры по модулям. Когда одна процедура вызывает другую, загружается весь модуль второй процедуры. Если одна процедура вызывает несколько процедур из разных модулей, все эти модули загружаются в память. Если же все процедуры находятся в одном модуле, они все загружаются одновременно.
Неправда, EXE проецируется полностью и ничего не подгружается. Если речь идет о работе в IDE, то да, только не загрузка а компиляция.
Цитата Сообщение от Dragokas Посмотреть сообщение
Не тратьте память бездумно.
Странно такое слышать после
Цитата Сообщение от Dragokas Посмотреть сообщение
Заранее определяйте массивы максимально возможного размера
Цитата Сообщение от Dragokas Посмотреть сообщение
Не нумеруйте каждую строку вашего кода, поскольку нумерация строк увеличивает размер вашей программы.
Неправда.
Цитата Сообщение от Dragokas Посмотреть сообщение
Убирайте неиспользуемые переменные и участки кода, так как они остаются в программе, и увеличивают как ее размер, так и выделяемую под нее оперативную память.
Неправда. Неиспользуемые переменные и процедуры вообще не попадают в скомпилированный файл (не говорю о методах).
Цитата Сообщение от Dragokas Посмотреть сообщение
Используйте функции API FindFirstFile, FindNextFile, и FindClose для быстрого поиска файлов и папок. Но помните, что не всегда обращение к функциям API быстрее. Это всегда сложнее, и иногда весьма рискованно, чем применение стандартных функций VB.
Если речь не идет о юникодных каталогах, то смысла нет.
Цитата Сообщение от Dragokas Посмотреть сообщение
Функции UCase$ и LCase$ позволяют вам осушествлять сравнения вне зависимости от регистра текста, но нижеследующие функции API гораздо быстрее:
Нужно использовать StrComp.
Цитата Сообщение от Dragokas Посмотреть сообщение
Например, этот код:
Visual Basic
1
2
3
4
5
Xsquare = x * x
Ysquare = y * y
a = 2 * Xsquare + 3 * Ysquare
b = 3 * Xsquare + 5 * Ysquare
If a + b > 50 Then ...
выполняется быстрее, чем следующий:
Visual Basic
1
2
3
If 2 * x * x + 3 * y * y + _
3 * x * x + 5 * y * y > 50 _
Then ...
Неправда, VB6 оптимизирует выражения.
6
Модератор
Эксперт функциональных языков программированияЭксперт Python
36606 / 20334 / 4221
Регистрация: 12.02.2012
Сообщений: 33,653
Записей в блоге: 13
11.01.2015, 13:49 5
Цитата Сообщение от The trick Посмотреть сообщение
Мой совет - выделять память порциями по 100 - 10000 элементов в зависимости от задачи.
- присоединяюсь!
2
Модератор
9725 / 3686 / 871
Регистрация: 22.02.2013
Сообщений: 5,531
Записей в блоге: 78
11.01.2015, 15:53 6
Немного от себя.
Для ускорения вызова API функций нужно использовать библиотеки типов, после этого функции добавляются в таблицу импорта.
Для ускорения вызовов методов COM объектов, также следует использовать библиотеки типов, если конечно это возможно, и вообще всегда стараться выполнять раннее связывание вместо использования позднего связывания.
Используйте числа с фиксированной запятой для ускорения вычисления каких либо значений:
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Dim z   As Long
Dim b() As Long
Dim i   As Long
Dim s   As Single
Dim p   As Long
 
ReDim b(10000)
 
z = 128  ' Число с фиксированной запятой (128/256) = 0.5
 
s = Timer
 
For p = 0 To 100000
    For i = 0 To UBound(b)
        ' Умножаем каждый элемент на 0.5
        b(i) = (b(i) * z) \ &H100
    Next
Next
 
MsgBox "Time: " & Timer - s & " sec."
 
s = Timer
 
For p = 0 To 100000
    For i = 0 To UBound(b)
        ' Умножаем каждый элемент на 0.5
        b(i) = b(i) * 0.5
    Next
Next
 
MsgBox "Time: " & Timer - s & " sec."
Пример: FixedPointTest.rar
Для ускорения некоторых расчетов можно воспользоваться свойствами компилятора, например чтобы использовать арифметику без ошибки - переполнений:
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Option Explicit
 
Private Declare Function GetMem4 Lib "msvbvm60" (Src As Any, Dst As Any) As Long
 
Dim cx      As Currency
 
Public Function Test() As Long
    Static ok   As Long
    Dim inIde   As Boolean          ' Обязательное условие - переменная уровня процедуры
 
    Debug.Assert MakeTrue(inIde)
        
    If inIde Then
        ' Этот код вообще не попадет в скомпилированный файл вместе с проверкой
        ' как-будто инструкции If нет, скомпилируется только ветка Else
        ' Это мы используем для обхода ошибки переполнения
        cx = 0@
        GetMem4 ok, cx
        cx = cx * 137687 + 12.3467@
        GetMem4 cx, ok
        
    Else
        ' Только этот код попадет в EXE
        ok = ok * 137687 + 123467
        
    End If
     
    Test = ok
    
End Function
 
Private Function MakeTrue(value As Boolean) As Boolean
    MakeTrue = True
    value = True
End Function
Вот во что скомпилируется функция Test:
[Статья] Как заставить Вашу программу на VB работать быстрее?

Функция MakeTrue вообще не попадет в EXE, если она объявлена в обычном модуле.
Пример: IDEOptimize.rar
Для того, чтобы ускорить вызов функций, нужно объявлять их в стандартном модуле. Если объявлять их в других модулях, то они превращаются в методы объектов и дополнительно передается 2 параметра, а также после каждого вызова идет проверка возвращаемого значения, что дополнительно требует времени.
Пример: CallOptimize.rar
PS. Позже еще напишу.
4
Модератор
Эксперт функциональных языков программированияЭксперт Python
36606 / 20334 / 4221
Регистрация: 12.02.2012
Сообщений: 33,653
Записей в блоге: 13
11.01.2015, 20:55 7
Цитата Сообщение от The trick Посмотреть сообщение
Для того, чтобы ускорить вызов функций, нужно объявлять их в стандартном модуле. Если объявлять их в других модулях, то они превращаются в методы объектов
- Вы имеете в виду, в модулях форм? Или смысл в том, что функции желательно объявлять в том же модуле (bas), где и вызвать?
0
Модератор
9725 / 3686 / 871
Регистрация: 22.02.2013
Сообщений: 5,531
Записей в блоге: 78
11.01.2015, 21:49 8
Цитата Сообщение от Catstail Посмотреть сообщение
Вы имеете в виду, в модулях форм?
Любой объект в дереве проектов является модулем. В любом объектном модуле кроме стандартного (.bas) модуля (формы, классы, страницы свойств, контролы и т.д.) объявленная функция является методом того объекта в котором объявлена. А как известно метод объекта первым параметром принимает указатель на объект (ObjPtr), а последним указатель на возвращаемое значение, т.е. у нас автоматически функция, к примеру, имеющая 3 параметра превращается в функцию имеющую 5 параметров. Реально возвращаемое значение является HRESULT, которое представляет код ошибки. Если метод будет публичным, то после каждого вызова дополнительно будет вызываться проверка этого HRESULT'а, что также требует времени.
Цитата Сообщение от Catstail Посмотреть сообщение
Или смысл в том, что функции желательно объявлять в том же модуле (bas), где и вызвать?
Это не имеет значения.
3
Модератор
9725 / 3686 / 871
Регистрация: 22.02.2013
Сообщений: 5,531
Записей в блоге: 78
11.01.2015, 22:13 9
Для копирования данных от 1 до 8 байт используйте функции GetMem и PutMem, которые намного быстрее чем RtlMoveMemory (CopyMemory). Также, к примеру, передавая в качестве значения параметра этих функций элемент массива (как обычно делают), это вызывает блокировку и разблокировку (__vbaAryLock, __vbaAryUnlock) массива каждый раз при вызове функции что требует дополнительного времени. Быстрее будет если передавать указатель на элемент полученный через VarPtr:
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
Option Explicit
 
Private Declare Function GetMem4 Lib "msvbvm60" (Src As Any, Dst As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
 
Dim arr() As Long
Dim i     As Long
Dim j     As Long
Dim s     As Single
Dim ptr   As Long
 
' // Èñïîëüçîâàíèå GetMem4 äëÿ êîïèðîâàíèÿ ñ ïðÿìîé ïåðåäà÷åé ìàññèâà
Private Sub cmdGetMem1_Click()
 
    s = Timer
    
    For i = 0 To 10000: For j = 0 To 10000
        GetMem4 1234&, arr(j)
    Next j, i
    
    MsgBox Timer - s & " sec."
    
End Sub
 
' // Èñïîëüçîâàíèå GetMem4 äëÿ êîïèðîâàíèÿ ñ ïîìîùüþ óêàçàòåëÿ
Private Sub cmdGetMem2_Click()
    Dim lptr    As Long
    
    s = Timer
    ptr = VarPtr(arr(0))
    
    For i = 0 To 10000
        lptr = ptr
        For j = 0 To 10000
            GetMem4 1234&, ByVal lptr
            lptr = lptr + 4
        Next j
    Next i
    
    MsgBox Timer - s & " sec."
        
End Sub
 
' // Èñïîëüçîâàíèå RtlMoveMemory äëÿ êîïèðîâàíèÿ ñ ïðÿìîé ïåðåäà÷åé ìàññèâà
Private Sub cmdRtlMoveMemory1_Click()
 
    s = Timer
    
    For i = 0 To 10000: For j = 0 To 10000
        CopyMemory arr(j), 1234&, 4
    Next j, i
    
    MsgBox Timer - s & " sec."
    
End Sub
 
' // Èñïîëüçîâàíèå RtlMoveMemory äëÿ êîïèðîâàíèÿ ñ ïîìîùüþ óêàçàòåëÿ
Private Sub cmdRtlMoveMemory2_Click()
    Dim lptr    As Long
    
    s = Timer
    ptr = VarPtr(arr(0))
    
    For i = 0 To 10000
        lptr = ptr
        For j = 0 To 10000
            CopyMemory ByVal lptr, 1234&, 4
            lptr = lptr + 4
        Next j
    Next i
    
    MsgBox Timer - s & " sec."
    
End Sub
 
Private Sub Form_Load()
    
    ReDim arr(10000)
 
End Sub
Вложения
Тип файла: rar GetMemOptimize.rar (10.3 Кб, 52 просмотров)
3
11508 / 3794 / 681
Регистрация: 13.02.2009
Сообщений: 11,197
12.01.2015, 14:45 10
48. Не вставляйте в цикл проверку со значением, возвращаемым функцией.

Например, этот код:
Visual Basic
1
2
i = 1
Do While i
выполняется значительно медленнее, чем этот:
Visual Basic
1
2
3
i_max = SlowFunction()
i = 1
Do While i
Что-то не понял?! По ходу опечатка?
В примере абсольтно одинаковые циклы.
До начала цикла задаётся значение i.
видимо где-то до Loop идёт наращивание.
Какое отношение ко времени работы цикла имеет переменная i_max вычисляемая до цикла?
0
Эксперт WindowsАвтор FAQ
17996 / 7697 / 892
Регистрация: 25.12.2011
Сообщений: 11,470
Записей в блоге: 16
12.01.2015, 15:38  [ТС] 11
Да. Там у них опечатка.
Объедините, пожалуйста, этих два кусочка кода вместе.
0
Эксперт WindowsАвтор FAQ
17996 / 7697 / 892
Регистрация: 25.12.2011
Сообщений: 11,470
Записей в блоге: 16
20.03.2016, 11:05  [ТС] 12
Цитата Сообщение от The trick Посмотреть сообщение
Используйте числа с фиксированной запятой для ускорения вычисления каких либо значений:
b(i) = (b(i) * z) \ &H100
b(i) = b(i) * 0.5
Это в том случае, если результатом операции должно быть целое число. Но тогда достаточно просто b(i) = b(i) \ 2

Если же результат записывается в переменную с плавающей запятой, то операция умножения будет быстрее операции деления:
Visual Basic
1
b(i) = b(i) * 0.5
Visual Basic
1
b(i) = b(i) / 2
1
Модератор
9725 / 3686 / 871
Регистрация: 22.02.2013
Сообщений: 5,531
Записей в блоге: 78
20.03.2016, 11:37 13
Цитата Сообщение от Dragokas Посмотреть сообщение
Это в том случае, если результатом операции должно быть целое число. Но тогда достаточно просто
Например с 0.7 такое не прокатит (я имею в виду \2).
Цитата Сообщение от Dragokas Посмотреть сообщение
Если же результат записывается в переменную с плавающей запятой, то операция умножения будет быстрее операции деления:
Ты можешь хранить результат также с фиксированной точкой, просто в данном примере это не нужно. А при выводе написать b(i) / &H100
1
Эксперт WindowsАвтор FAQ
17996 / 7697 / 892
Регистрация: 25.12.2011
Сообщений: 11,470
Записей в блоге: 16
20.03.2016, 11:47  [ТС] 14
Цитата Сообщение от The trick Посмотреть сообщение
Например с 0.7 такое не прокатит (я имею в виду \2).
Ну да.
( x * 7 ) \ 10

И ты используешь 16-ричные числа в делителе, это (выравнивание) тоже имеет какой-то особый смысл с точки зрения скорости ?
0
Модератор
9725 / 3686 / 871
Регистрация: 22.02.2013
Сообщений: 5,531
Записей в блоге: 78
20.03.2016, 13:38 15
Цитата Сообщение от Dragokas Посмотреть сообщение
И ты используешь 16-ричные числа в делителе, это (выравнивание) тоже имеет какой-то особый смысл с точки зрения скорости ?
Наглядность. Отдаю 8 бит под дробные значения. Хотя может в некоторых ситуациях это даже быстрее т.к. такие деления компилируются в сдвиги.
1
Эксперт WindowsАвтор FAQ
17996 / 7697 / 892
Регистрация: 25.12.2011
Сообщений: 11,470
Записей в блоге: 16
23.04.2016, 19:39  [ТС] 16
The trick, можно для тебя, как спеца в этих штуках, оставить такие задачки ?
Что быстрее:

1) Exit For или Exit Sub (Function),
если подразумевается, что после выхода из цикла подпрограмма завершается.

2) Операция "var > 0" или операция "var <> 0"

3) GetMem4 ByVal VarPtr(bData(0)), ByVal VarPtr(lData)
или
lData = bData(0) + bData(1) * 256&
0
Модератор
Эксперт функциональных языков программированияЭксперт Python
36606 / 20334 / 4221
Регистрация: 12.02.2012
Сообщений: 33,653
Записей в блоге: 13
24.04.2016, 09:44 17
Dragokas, хоть вопрос и не ко мне, выскажу свое оценочное мнение. Мне кажется:

1) Exit Sub должно быть быстрее
2) операции > и <> по скорости одинаковы
3) GetMem быстрее
1
Модератор
9725 / 3686 / 871
Регистрация: 22.02.2013
Сообщений: 5,531
Записей в блоге: 78
24.04.2016, 10:33 18
Цитата Сообщение от Dragokas Посмотреть сообщение
Exit For или Exit Sub (Function),
если подразумевается, что после выхода из цикла подпрограмма завершается.
Одно и тоже.
Цитата Сообщение от Dragokas Посмотреть сообщение
Операция "var > 0" или операция "var <> 0"
Одно и тоже.
Цитата Сообщение от Dragokas Посмотреть сообщение
GetMem4 ByVal VarPtr(bData(0)), ByVal VarPtr(lData)
или
lData = bData(0) + bData(1) * 256&
Второй вариант быстрее.
3
Эксперт WindowsАвтор FAQ
17996 / 7697 / 892
Регистрация: 25.12.2011
Сообщений: 11,470
Записей в блоге: 16
14.05.2017, 18:10  [ТС] 19
Что будет быстрее для разбиения числа (в идеале нужно Currency) на байты (тип byte) - GetMem1 либо побитовый "И" ?

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Option Explicit
 
Private Declare Function GetMem1 Lib "msvbvm60.dll" (src As Any, dst As Any) As Long
 
Private Sub Form_Load()
    Dim l As Long
    Dim b As Byte
    
    l = -1
    b = CByte(((l And &HFF000000) \ &H1000000) And &HFF&)
    
    Debug.Print Hex(b)
    b = 0
 
    GetMem1 ByVal VarPtr(l) + 3, b
    
    Debug.Print Hex(b)
End Sub
Конечно, учитывая специфику бейсика, где Currency нельзя написать как операнд оператора "И", выбор очевиден.
Но, можно ли написать (способна ли) ассемблерную вставку с использованием одной инструкции с оператором "И", которая работала бы быстрее GetMem1 ?

Добавлено через 4 минуты
В принципе тут разница только в том, что для GetMem1 затраты уйдут на (по примеру выше):
- получить адрес, +3, скопировать участок памяти.
- вариант с ASM наверное будет ещё сложнее.

Так что вопрос, наверное, отпал сам собой.
0
Модератор
9725 / 3686 / 871
Регистрация: 22.02.2013
Сообщений: 5,531
Записей в блоге: 78
14.05.2017, 20:12 20
Dragokas, быстрее всего будет GetMem8 в 8-ми байтовый массив, и потом уже обращаться к нужным байтам.
2
14.05.2017, 20:12
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.05.2017, 20:12
Помогаю со студенческими работами здесь

Как заставить программу работать постоянно?
Здравствуйте! Мне нужно сделать так, что бы программа работала постоянно. Я уже попытался...

Как заставить эту программу работать в VC++ форм
Уважаемые программисты помогите, срочно нужен ответ #include &lt;vcl.h&gt; #pragma hdrstop #include...

Как заставить программу работать через прокси?
Кто нибудь имеет примерчик как заставить готовую прогу (типа чата) работать с возможностью прокси?...

Как заставить программу работать без остановки?
Здравствуйте, недавно начал изучать objective-c. И вот вопрос, например есть код и как его работать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru