О производительности динамических массивов...

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

О производительности динамических массивов...

Сообщение beria » 07.09.2022 08:33:55

Простой тест, с одинаковым функционалом для динамических массивов и простого распределения памяти для ссылочных переменных
Код: Выделить всё
program project1;

{$mode objfpc}{$H+}

uses
{$IFDEF UNIX}
  cthreads,
     {$ENDIF}
  Classes,
  SysUtils { you can add units after this };

  var
  Ar: array of byte;
  P:  PByteArray;
  i,t : longint;
begin
  t := GetTickCount64;
  for i := 0 to 100000 do
  begin
    SetLength(Ar, 1000000);
    Ar[100] := 100;
    SetLength(Ar, 500);
    if Ar[100] <> 100 then writeln('error:SetLength');
    Ar[9] := 9;
    SetLength(Ar, 0);
  end;
  writeln(GetTickCount64 - t);
  t := GetTickCount64;
  for i := 0 to 100000 do
  begin
    GetMem(P, 1000000);
    (P^)[100] := 100;
    ReallocMem(P, 500);
   if (P^)[100] <> 100 then writeln('error:ReallocMem');
    (P^)[9] := 9;
    FreeMem(P);
  end;
  writeln(GetTickCount64 - t);
  readln;
end.


Результат работы:
5187
16
то есть второй вариант более чем в 100 раз быстрее.. А тогда, вопрос, а какие такие особые фичи, ну кроме того что выход из программы удалит и все массивы, дают динамические массивы, если по скорости работы (используется стандартный менеджер памяти), они проигрывают...
Аватара пользователя
beria
постоялец
 
Сообщения: 130
Зарегистрирован: 29.09.2016 08:57:13

Re: О производительности динамических массивов...

Сообщение zub » 07.09.2022 10:53:03

https://www.freepascal.org/docs-html/rt ... ength.html
>>In case the length is set to a larger length than the current one, the new elements are zeroed out for a dynamic array. For a string, the string is zero-terminated at the correct length.
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: О производительности динамических массивов...

Сообщение iskander » 07.09.2022 11:02:25

beria писал(а):А тогда, вопрос, а какие такие особые фичи, ну кроме того что выход из программы удалит и все массивы, дают динамические массивы

Прозрачная инициализация/финализация элементов массива.
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

Re: О производительности динамических массивов...

Сообщение runewalsh » 07.09.2022 12:08:26

GetMem не заполняет память нулями, SetLength заполняет (или даже вызывает кастомные Initialize/Finalize, что ещё медленнее). Если использовать GetMem+FillChar, будет одинаково.

Но если ты вызвал SetLength, то ты эти элементы собираешься использовать, то есть будешь с ними делать что-то, на фоне чего их зануление потеряется. Попробуй добавить в цикл хоть какую-то обработку, например, подсчёт суммы всех элементов.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 578
Зарегистрирован: 27.04.2010 00:15:25

Re: О производительности динамических массивов...

Сообщение Alex2013 » 07.09.2022 12:28:30

runewalsh писал(а):GetMem не заполняет память нулями, SetLength заполняет (или даже вызывает кастомные Initialize/Finalize, что ещё медленнее). Если использовать GetMem+FillChar, будет одинаково.

Все еще хуже! SetLength в цикле натуральная "смерть хомячкам" . ( я когда то смотрел код и там по сути масив ЦЕЛИКОМ пересоздается с копированием содержимого в новую область ). Зачем так сделано можно только догадываться .Так что лучше считать что SetLength срабатывает только один раз при создании массива ( ну еще освободить память можно ).

Для практики лучше высчитать максимальный размер заранее и "не мучать скотинку" (SetLength ) лишний раз. Если содержимое масиа неважно то можно обнулить создать по новой. Но лучше уж отказаться от такого "ненавязчивого сервиса" например в пользу TList и его производных.
Последний раз редактировалось Alex2013 07.09.2022 12:48:58, всего редактировалось 2 раз(а).
Alex2013
долгожитель
 
Сообщения: 2957
Зарегистрирован: 03.04.2013 11:59:44

Re: О производительности динамических массивов...

Сообщение beria » 07.09.2022 12:43:44

runewalsh писал(а):GetMem не заполняет память нулями, SetLength заполняет (или даже вызывает кастомные Initialize/Finalize, что ещё медленнее). Если использовать GetMem+FillChar, будет одинаково.

Но если ты вызвал SetLength, то ты эти элементы собираешься использовать, то есть будешь с ними делать что-то, на фоне чего их зануление потеряется. Попробуй добавить в цикл хоть какую-то обработку, например, подсчёт суммы всех элементов.

Целых два разных рассчетных цикла в разных состояниях..

Код: Выделить всё
program project1;

{$mode objfpc}{$H+}

uses
{$IFDEF UNIX}
  cthreads,
        {$ENDIF}
  Classes,
  SysUtils { you can add units after this };

const
  loop = 100000;
  loop2 = 200;

var
  Ar: array of byte;
  P: PByteArray;
  i, j, k, w, t: longint;
begin
  t := GetTickCount64;
  for i := 0 to loop do
  begin
    SetLength(Ar, loop);
    for j := 0 to loop - 1 do Ar[j] := j;
    k := 0;
    for  j := 0 to loop - 1 do Inc(k, Ar[j]);
    SetLength(Ar, loop2);
    w := 0;
    for  j := 0 to loop2 - 1 do Inc(w, Ar[j]);
    SetLength(Ar, 0);
  end;
  writeln(GetTickCount64 - t);
  writeln(k);
  writeln(w);
  t := GetTickCount64;
  for i := 0 to loop do
  begin
    GetMem(P, loop);
    for j := 0 to loop - 1 do (P^)[j] := j;
    k := 0;
    for  j := 0 to loop - 1 do Inc(k, (P^)[j]);
    ReallocMem(P, loop2);
    w := 0;
    for  j := 0 to loop2 - 1 do Inc(w, (P^)[j]);
    FreeMem(P);
  end;       
  writeln(GetTickCount64 - t);
  writeln(k);
  writeln(w);
  readln;
end.



Результат
9875
12742320
19900
7437
12742320
19900

То есть и тут динамический массив медленнее, пусть и на всего 30%, но тоже прилично.... Подозреваю, что время доступа по ссылке, одинаково, а вот перераспределения памяти у массива медленнее.. Кстати размер выделенной памяти можно получить через MemSize(p)

зы: "GetMem не заполняет память нулями, " Имхо совсем не нужная везде задача и даже лишняя, как и дефолтное обнуление всех переменных из var. Тем более fillChar, если надо универсальнее...
Аватара пользователя
beria
постоялец
 
Сообщения: 130
Зарегистрирован: 29.09.2016 08:57:13

Re: О производительности динамических массивов...

Сообщение Alex2013 » 07.09.2022 13:40:44

Придания глубокой старины.
Так работает SetLength
(2 "с копейками" секунды это даже не заполнение, а удаление что еще веселее )

Изображение
Это у Зуба у меня на "рабочей лошадке"(Старый ноутбук с трудом тянущий Win10 ) сейчас вообще
Press AddItems or RemoveItems 0.334sec 9.443sec (64 бита) и 0.535sec 9.302sec (32 бита) )
А так Tlist и TStringlist
Изображение
(это 32 бита на 64 битной оси в режиме 64 бита вообще 0.0127 c )
А очищает у меня так " Список очищен за 0.0012 c" (Иногда вообще "0 с" что показывает что расчет времени сотых и тысячных долях секунды просто погрешность вычислений )



См. тему
Посоветуйте компонент типа ListView но с форматированием
Последний раз редактировалось Alex2013 07.09.2022 15:38:27, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2957
Зарегистрирован: 03.04.2013 11:59:44

Re: О производительности динамических массивов...

Сообщение zub » 07.09.2022 15:19:01

>>зы: "GetMem не заполняет память нулями, " Имхо совсем не нужная везде задача и даже лишняя, как и дефолтное обнуление всех переменных из var. Тем более fillChar, если надо универсальнее...
если ненужная, используешь классические массивы. Скорость одинаковая, за исключением этого момента
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: О производительности динамических массивов...

Сообщение runewalsh » 07.09.2022 15:21:11

beria писал(а):Результат
9875
12742320
19900
7437
12742320
19900


У меня, без изменений кода, x86-64, -O3:
9031
12742320
19900
9578
12742320
19900
:>
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 578
Зарегистрирован: 27.04.2010 00:15:25

Re: О производительности динамических массивов...

Сообщение beria » 07.09.2022 15:47:48

runewalsh писал(а):У меня, без изменений кода, x86-64, -O3

Ещё раз пересобрал. Все цифры (+- немного на погрешность) повторились. Подозреваю у вас где-то включена отладка, что все объясняет.... FPC- транк c гитлаба.

Добавлено спустя 1 минуту 31 секунду:
zub писал(а): используешь классические массивы.

Классические массивы могут динамически менять размер? :shock: :shock: :shock: :shock:
Аватара пользователя
beria
постоялец
 
Сообщения: 130
Зарегистрирован: 29.09.2016 08:57:13

Re: О производительности динамических массивов...

Сообщение Дож » 07.09.2022 16:06:04

beria, вы в своём коде после GetMem не вызываете FillChar(P^, loop, 0), скорее всего из-за этого возникает такая разница. У меня FillChar уравнивает показатели производительности.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: О производительности динамических массивов...

Сообщение beria » 07.09.2022 16:25:50

Дож писал(а):GetMem не вызываете FillCha

А зачем? Сначала обнулять, и только потом заполнять данными - бессмысленная и по моему ненужная вещь. Поэтому я выше и написал что " перераспределения памяти у массива медленнее"
Если чисто распределение памяти для данных, как в первом тесте показано - так вообще GetMem работает более чем в 150 раз быстрее
Аватара пользователя
beria
постоялец
 
Сообщения: 130
Зарегистрирован: 29.09.2016 08:57:13

Re: О производительности динамических массивов...

Сообщение Дож » 07.09.2022 16:38:15

А зачем?

Чтобы не подозревать массив в "медленном перераспределении".
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: О производительности динамических массивов...

Сообщение iskander » 07.09.2022 16:53:42

beria писал(а):А зачем? Сначала обнулять, и только потом заполнять данными - бессмысленная и по моему ненужная вещь.

А попробуйте проверить это предположение для строк, например.
iskander
энтузиаст
 
Сообщения: 590
Зарегистрирован: 08.01.2012 18:43:34

Re: О производительности динамических массивов...

Сообщение zub » 07.09.2022 17:27:06

>>лассические массивы могут динамически менять размер? :shock: :shock: :shock: :shock:
а че нет? выделяешь память, копируешь старое, и не инитишь новое. какраз ка ты хочешь

>>А попробуйте проверить это предположение для строк, например.
строки какраз SetLength`ом не инятятся, в там только в конце 0 пишется, в середине мусор будет.
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

След.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 75

Рейтинг@Mail.ru