В статье Романа Кунина "Оптимизация кода: память" рассмотрены две функции на C++, которые суммируют элементы матрицы. Они практически одинаковы, только первая функция обходит элементы матрицы по строкам, а вторая по столбцам. Проведем подобный тест на Delphi 7 и Delphi 10.3.2.
В отличии от оригинального теста, в котором суммируют элементы матрицы я предлагаю еще измерить скорость заполнения матрицы.
Эта была матрица значений типа integer, теперь заменим "Array of Array of Integer" на "Array of Array of Int64" и проверим скорость работы с матрицей, содержащей значения типа int64.
Как видно из таблиц с результатами, скорость обработки матрицы по строкам со времен Delphi 7 не изменилась. А вот скорость обработки ее по столбцам, значительно выросла. Так, что плюсик в карму разработчикам Delphi.
Такого впечатляющего результата как у Романа (разницы в 25 раз), у меня не получилось (будем патриотично думать, что Delphi работает с памятью лучше, чем C++), но мои тесты тоже показывают, что двумерный массив правильно обходить по строкам.
В отличии от оригинального теста, в котором суммируют элементы матрицы я предлагаю еще измерить скорость заполнения матрицы.
Результаты:program Matrix; {$APPTYPE CONSOLE} {$R *.res} uses SysUtils; const ciMaxIndex = 9999; procedure ByRow; var a: Array of Array of Integer; c, i, j, iSum: Integer; dt: TDateTime; begin SetLength(a, ciMaxIndex + 1, ciMaxIndex + 1); dt := Now; for c := 1 to 10 do for i := 0 to ciMaxIndex do for j := 0 to ciMaxIndex do a[i, j] := 1; Writeln(FormatDateTime('ss.zzz', (Now - dt) /10)); iSum := 0; dt := Now; for c := 1 to 10 do for i := 0 to ciMaxIndex do for j := 0 to ciMaxIndex do Inc(iSum, a[i, j]); Writeln(FormatDateTime('ss.zzz', (Now - dt) /10)); SetLength(a, 0); WriteLn(iSum); end; procedure ByCol; var a: Array of Array of Integer; c, i, j, iSum: Integer; dt: TDateTime; begin SetLength(a, ciMaxIndex + 1, ciMaxIndex + 1); dt := Now; for c := 1 to 10 do for i := 0 to ciMaxIndex do for j := 0 to ciMaxIndex do a[j, i] := 1; Writeln(FormatDateTime('ss.zzz', (Now - dt) /10)); iSum := 0; dt := Now; for c := 1 to 10 do for i := 0 to ciMaxIndex do for j := 0 to ciMaxIndex do Inc(iSum, a[j, i]); Writeln(FormatDateTime('ss.zzz', (Now - dt) /10)); SetLength(a, 0); Writeln(iSum); end; begin ByRow; ByCol; end.
Компилятор | Заполнение | Чтение | ||||
по строкам | по столбцам | разница | по строкам | по столбцам | разница | |
Delphi 7 | 0.055 мс | 1.281 мс | 23.29 | 0.140 мс | 1.194 мс | 8.53 |
Delphi 10.3.2 32-бит | 0.055 мс | 0.692 мс | 12.58 | 0.141 мс | 0.712 мс | 5.05 |
Delphi 10.3.2 64-бит | 0.134 мс | 0.661 мс | 4.93 | 0.159 мс | 0.732 мс | 4.60 |
Компилятор | Заполнение | Чтение | ||||
по строкам | по столбцам | разница | по строкам | по столбцам | разница | |
Delphi 7 | 0.109 мс | 0.881 мс | 8.08 | 0.167 мс | 1.161 мс | 6.95 |
Delphi 10.3.2 32-бит | 0.108 мс | 0.823 мс | 7.62 | 0.166 мс | 1.065 мс | 6.416 |
Delphi 10.3.2 64-бит | 0.142 мс | 0.849 мс | 5.98 | 0.165 мс | 1.029 мс | 6.24 |
Как видно из таблиц с результатами, скорость обработки матрицы по строкам со времен Delphi 7 не изменилась. А вот скорость обработки ее по столбцам, значительно выросла. Так, что плюсик в карму разработчикам Delphi.
Такого впечатляющего результата как у Романа (разницы в 25 раз), у меня не получилось (будем патриотично думать, что Delphi работает с памятью лучше, чем C++), но мои тесты тоже показывают, что двумерный массив правильно обходить по строкам.
"Когда мы работаем над данными, желательно чтобы они находились в памяти рядом. Обход матрицы по столбцам имеет плохую локальность, потому что матрица хранится в памяти построчно."
©2016 Роман Кунин "Оптимизация кода: память"
Комментариев нет:
Отправить комментарий