В статье Романа Кунина "Оптимизация кода: память" рассмотрены две функции на 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 Роман Кунин "Оптимизация кода: память"
Комментариев нет:
Отправить комментарий