Допустим, что у нас есть форма Form2, на которой расположен компонент ListBox, содержащий список чисел. Нам нужно вывести на экран список из Li stBox, в котором к каждому элементу будет прибавлено число, равное количеству элементов. Вот пример решения задачи:

var
і: Integer: begin
for і •= 0 to Form2.Listbox.Iterns.Count-1 do begin
Canvas.TextOut(10. i*16. StrToInt(Form2.Listbox.Items[i])+ Form2.Listbox.Items.Count):
end:
end;

Здесь запускается цикл перебора всех элементов из списка. На экран выводится і-й элемент, которому прибавлено количество элементов в компоненте ListBox.

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

Рассмотрим, как определяется количество элементов в списке Li stBox. Для этого нужно "взять" форму Form2, найти на ней компонент списка Li stbox, затем обратиться к элементам списка Items и только потом определить количество Count. Посчитайте, сколько нужно выполнить операций? И эта цепочка операций выполняется несколько раз. Во второй раз мы обращаемся к количеству элементов в цикле. Сейчас не будем обращать внимание на цикл, но такое длинное обращение выполняется не один раз, и это не может не волновать.

Если бы мы писали код на языке ассемблер, то число, равное количеству элементов, можно было сохранить в регистре, что значительно повысило бы производительность. Операции с регистрами выполняются быстрее, чем с памятью. Но компилятор Delphi может не распознать явной оптимизации. Он может интерпретировать код таким образом что перед каждым обращением к свойству Count списка число будет копироваться в регистр ЕАХ, а это лишние затраты времени. Для ускорения доступа можно использовать такой пример:

var
iCount, i Integer: begin
iCount := Form2.Listbox.Iterns.Count:
for i := 0 to iCount-1 do
begin
Canvas.TextOut(10. i*16. StrToInt(Form2.Listbox.Items[i])+iCount):
end:
end:

Здесь мы объявили новую переменную, но зато сократили число обращений к длинной цепочке до одного. В самом начале значение свойства Count сохраняется в локальной переменной iCount, в которой осуществляется дальнейшая работа. Таким образом, производительность сильно повышается, особенно если цикл будет выполняться сотни раз.

2.15. Сокращение цепочек

Рис. 2.10. Код на языке ассемблер, который сгенерировал Delphi, с использованием длинных цепочек

Теперь немного изменим задачу. Допустим, что нам надо заполнить элементы списка следующим образом:

var
i: Integer: begin
for i := 0 to Form2.Listbox.Items.Count-1 do Form2.Listbox.Items[i] := IntToStr(i):
end;

В примере две длинные цепочки, и они разные. Несмотря на это, мы можем сократить цепочки, создав код, более быстрый в исполнении:

var
i: Integer: si: TStrings: begin
si := Form2.Listbox.Items: fbr i := 0 to si.Count-1 do sl[i] := IntToStr(i):
end:

Мы работаем с элементами свойства Items компонента ListBox. Значение свойства имеет тип TStrings. Указатель на Items сохраняется в локальной переменной, в которой осуществляется дальнейшая работа.

2.15. Сокращение цепочек

Рис. 2.11. Код на языке ассемблер, котбрый сгенерировал Delphi, без использования длинных цепочек

При использовании длинных цепочек результирующий код всегда будет больше. На рис. 2.10 представлено окно отладчика Delphi. Рамкой выделен ассемблерный код цикла вплоть до выхода из процедуры.

На рис. 2.11 вы можете увидеть аналогичный код, но без использования цепочек. Рамкой выделен цикл и даже на глаз видно, что он меньше. Конечно же, результирующий код почти одинаков по размеру (и все же без использования цепочек меньше на 2 команды), потому что во втором случае добавляются три ассемблерные команды для сохранения цепочки в локальной переменной. Скорость выполнения программы без цепочек будет выше, так как удалено самое слабое звено - цикл, который выполняется неоднократно. Таким образом, во втором случае нужно выполнять меньше операций.

Если внутри цикла было хотя бы два обращения к цепочке, то можно сократить код намного больше и выиграть в скорости.

Мы рассматривали цикл с длинной цепочкой, чтобы вы могли ощутить выгоду от приема оптимизации. Даже если у вас нет цикла, но в процедуре есть несколько обращений к какому-то элементу цепочки, то польза от оптимизации существенна.

2.14.2. Внешний ассемблер || Оглавление || 2.15.1. Разрыв цепочек


Delphi в шутку и всерьез: что умеют хакеры



Новости за месяц

  • Декабрь
    2021
  • Пн
  • Вт
  • Ср
  • Чт
  • Пт
  • Сб
  • Вс
  • 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