Generics под капотом
От: swame  
Дата: 21.01.23 09:49
Оценка:
Встречались ли где — нибудь рекомендации, как лучше писать код с Generics, чтобы меньше нагружать компилятор?
Например, насколько будет разница в используетмой памяти, скорости компиляции, итоовом коде при компиляции при таком использованнии Generics:

  Код1
TStringMap = TDictionary<string,string>;

class TMyClass
 FMap : TStringMap;
 constructor  Create;
end;

 constructor  TMyClass.Create;
  begin
   inherited;
   FMap := TStringMap.Create; 
  end;


или

  Код2
class TMyClass;
 FMap : TDictionary<string,string>;
 constructor  Create;
end;

 constructor  TMyClass.Create;
  begin
   inherited;
   FMap := TDictionary<string,string>.Create; 
  end;


Проблема в том , что заканчивается память при компиляции из среды (bds.exe доходит до предела 3Гб).
Программа порядка 1,8 млн строк (только своих) + сторонние компоненты.
Около 2500 только своих модулей
Delphi 10.4.2

Подозреваю что больше всего нагружает компилятор циклические зависимости между модулями (но они почти все разрулены) и сложные конструкции с Generics.
В программе много кода в стиле типа такого

  Код3
procedure TfrmTopGraphDM.actSaveNearestGIds4ShRPExecute(Sender: TObject);
type
  RPair = record
    nb1, nb2: TNB;
  end;
var
  sch: TSchemeSet;
  lPairs: TRStream<String>;
begin
  sch := App.SDEDocs.Active;
  if not Assigned(sch) then exit;

  lPairs :=
    TRStream<TNB>.stream<Integer>(sch.Techs)
      .map<TNB>(
        procedure (aNB: TNB; var aMap: TProc<TNB>)
        begin
          if (aNB.IsChildOrEqual(ttcPowerTransformer) and TCEAPI.isShRP(aNB)) then
            aMap(aNB);
        end)
      .map<RPair>(
        procedure (aNB: TNB; var aMap: TProc<RPair>)
        var
          lSwitch: TCE;
          lPair: RPair;
        begin
          lSwitch := TRStream<TNB>
            .just(aNB)
            .map<TCE>(TCeAPI.ce)
            .map(TCeAPI.find(TCERules.windingExtraTerminalsRules,
                  function (aCe: TCE): Boolean
                  begin
                    Result := aCe.IsChildOrEqual(ttcSwitch) and not TCEAPI.isCandle(aCE) and (TCEAPI.globalId(aCE) <> '');
                  end, True))
            .first
            .toArray()
            .firstItem;
          if Assigned(lSwitch) then
          begin
            lPair.nb1 := aNB;
            lPair.nb2 := lSwitch;
            aMap(lPair);
          end;
        end)
      .map<String>(
        procedure (aPair: RPair; var aMap: TProc<String>)
        begin
          aMap(TTopGraphUtils.SaveNB(aPair.nb1) + CSV_DELIMETER + TTopGraphUtils.SaveNB(aPair.nb2));
        end);

  TRIO.saveToFile(lPairs);
end;


Где составляющие выражений часто повторяются в разных методах.
Вопрос, как его лучше оптимизировать для компилятора.
Отредактировано 21.01.2023 10:08 swame . Предыдущая версия . Еще …
Отредактировано 21.01.2023 9:58 swame . Предыдущая версия .
Отредактировано 21.01.2023 9:56 swame . Предыдущая версия .
Отредактировано 21.01.2023 9:54 swame . Предыдущая версия .
Отредактировано 21.01.2023 9:53 swame . Предыдущая версия .
Отредактировано 21.01.2023 9:53 swame . Предыдущая версия .
Отредактировано 21.01.2023 9:52 swame . Предыдущая версия .
Отредактировано 21.01.2023 9:51 swame . Предыдущая версия .
Re: Generics под капотом
От: rudzuk  
Дата: 21.01.23 10:31
Оценка:
Здравствуйте, swame, Вы писали:

Можно попробовать включить сборку внешним компилятором. Ну и от циклических зависимостей лучше избавиться.
avalon/3.0.2
Re[2]: Generics под капотом
От: swame  
Дата: 21.01.23 10:41
Оценка:
Здравствуйте, rudzuk, Вы писали:

R>Здравствуйте, swame, Вы писали:


R>Можно попробовать включить сборку внешним компилятором. Ну и от циклических зависимостей лучше избавиться.


Из командной строки оно пока собирается.
Надо, чтоб работала отладка.
Развесистые циклические зависимости могут сильно гадить, но они вычищены,
остались только сложно устранимые зависимости межлу 2-3 модулями, думаю сейчас они не делают погоды.
Re[3]: Generics под капотом
От: rudzuk  
Дата: 21.01.23 11:01
Оценка:
Здравствуйте, swame, Вы писали:

s> R>Можно попробовать включить сборку внешним компилятором. Ну и от циклических зависимостей лучше избавиться.


s> Из командной строки оно пока собирается.


Не, я о настройке компиляции Use MSBuild externally to compile

s> Надо, чтоб работала отладка.


Для этого нужно включить Include remote debug symbols в настройке линкера.
avalon/3.0.2
Re: Generics под капотом
От: rudzuk  
Дата: 21.01.23 11:12
Оценка:
Здравствуйте, swame, Вы писали:

Ну и о дженериках. Дженерик это только заготовка, поэтому, сколько бы ни было объявлений, например, TDictionary<string, string> это всегда будет один и тот же конкретизированный тип.
avalon/3.0.2
Re[2]: Generics под капотом
От: swame  
Дата: 21.01.23 11:27
Оценка:
Здравствуйте, rudzuk, Вы писали:

R>Здравствуйте, swame, Вы писали:


R>Ну и о дженериках. Дженерик это только заготовка, поэтому, сколько бы ни было объявлений, например, TDictionary<string, string> это всегда будет один и тот же конкретизированный тип.


ТО есть создается один тип в exe при использовании количества конструкций TDictionary<string, string> такого дженерика в exe?
Возможно так и есть в простых случаях.
Есть еще варианты дженериков от дженериков, методов от дженериков. Все это у нис используется.
В любом случае, для того чтобы компилятору понять, что уже есть такая сущность, нужна память и время.
Вот и хотелось разобраться, что для этого существенно что нет, прежде чем переделывать лесятки тысях строк в коде.
Потому как померять эффект при небольщом количестве изменений непонятно.
Re[4]: Generics под капотом
От: swame  
Дата: 21.01.23 11:28
Оценка:
Здравствуйте, rudzuk, Вы писали:

R>Здравствуйте, swame, Вы писали:


s>> R>Можно попробовать включить сборку внешним компилятором. Ну и от циклических зависимостей лучше избавиться.


s>> Из командной строки оно пока собирается.


R>Не, я о настройке компиляции Use MSBuild externally to compile


Не очень вариант, так компилится намного медленней.
Re[3]: Generics под капотом
От: rudzuk  
Дата: 21.01.23 11:36
Оценка: 4 (1)
Здравствуйте, swame, Вы писали:

s> R>Ну и о дженериках. Дженерик это только заготовка, поэтому, сколько бы ни было объявлений, например, TDictionary<string, string> это всегда будет один и тот же конкретизированный тип.


s> ТО есть создается один тип в exe при использовании количества конструкций TDictionary<string, string> такого дженерика в exe?


Да.

s> Есть еще варианты дженериков от дженериков, методов от дженериков. Все это у нис используется.


По идее, это роли играть не должно.

s> В любом случае, для того чтобы компилятору понять, что уже есть такая сущность, нужна память и время.

s> Вот и хотелось разобраться, что для этого существенно что нет, прежде чем переделывать лесятки тысях строк в коде.
s> Потому как померять эффект при небольщом количестве изменений непонятно.

Вообще, дженерики, конечно затрудняют компиляцию и увеличивают количество генерируемого кода, априори. Поэтому, если есть возможность их не использовать, то лучше ею воспользоваться. По количеству кода в конкретных юнитах может помочь https://github.com/VilleKrumlinde/delphiunitsizes
avalon/3.0.2
Re: Generics под капотом
От: BlackEric http://black-eric.lj.ru
Дата: 21.01.23 11:46
Оценка: +1
Здравствуйте, swame, Вы писали:

Разбивайте приложение на проекты: dll, bpl и т.д. Что бы можно было собирать независимо по частям. Это резко упростит сбоку и отладку.
https://github.com/BlackEric001
Re[4]: Generics под капотом
От: BlackEric http://black-eric.lj.ru
Дата: 21.01.23 11:47
Оценка:
Здравствуйте, rudzuk, Вы писали:

R>Вообще, дженерики, конечно затрудняют компиляцию и увеличивают количество генерируемого кода, априори. Поэтому, если есть возможность их не использовать, то лучше ею воспользоваться. По количеству кода в конкретных юнитах может помочь https://github.com/VilleKrumlinde/delphiunitsizes


За 13 лет прошедших с выхода Delphi 2010 ничего не изменилось...
https://github.com/BlackEric001
Re[5]: Generics под капотом
От: rudzuk  
Дата: 21.01.23 12:00
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE> R>Вообще, дженерики, конечно затрудняют компиляцию и увеличивают количество генерируемого кода, априори. Поэтому, если есть возможность их не использовать, то лучше ею воспользоваться. По количеству кода в конкретных юнитах может помочь https://github.com/VilleKrumlinde/delphiunitsizes


BE> За 13 лет прошедших с выхода Delphi 2010 ничего не изменилось...


Это не столько к компилятору претензия, сколько к самим дженерикам.
avalon/3.0.2
Re[5]: Generics под капотом
От: swame  
Дата: 21.01.23 12:57
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Здравствуйте, rudzuk, Вы писали:


R>>Вообще, дженерики, конечно затрудняют компиляцию и увеличивают количество генерируемого кода, априори. Поэтому, если есть возможность их не использовать, то лучше ею воспользоваться. По количеству кода в конкретных юнитах может помочь https://github.com/VilleKrumlinde/delphiunitsizes


BE>За 13 лет прошедших с выхода Delphi 2010 ничего не изменилось...


С самого начала работаю с ними, все — таки улучшилось.

https://delphi-developers-archive.blogspot.com/2016/05/blog-post-compilation-for-delphi-win32.html


https://it-blackcat.blogspot.com/2021/03/compiler-performance-improvements-in-Delphi-10-4-2.html


и другие оптимизации, оптимизирована библиотека контейнеров.
Отредактировано 21.01.2023 13:45 swame . Предыдущая версия .
Re[4]: Generics под капотом
От: swame  
Дата: 21.01.23 13:00
Оценка:
R>Вообще, дженерики, конечно затрудняют компиляцию и увеличивают количество генерируемого кода, априори. Поэтому, если есть возможность их не использовать, то лучше ею воспользоваться. По количеству кода в конкретных юнитах может помочь https://github.com/VilleKrumlinde/delphiunitsizes

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

Программка очень полезная, спасибо
Re[2]: Generics под капотом
От: swame  
Дата: 21.01.23 13:05
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Здравствуйте, swame, Вы писали:


BE>Разбивайте приложение на проекты: dll, bpl и т.д. Что бы можно было собирать независимо по частям. Это резко упростит сбоку и отладку.


Это очевидно, но у нас специфика программы такая, что все попытки рефакторинга на "удаленные фасады" и прочее ведет к дикому усложнению и торможению влаимодействия модулей.
А те части, которые легко логически отделяются, и так небольшие.
Что можно, выделяем.
Re[2]: Generics под капотом
От: Khimik  
Дата: 22.01.23 18:35
Оценка:
Здравствуйте, rudzuk, Вы писали:

R>Ну и о дженериках. Дженерик это только заготовка, поэтому, сколько бы ни было объявлений, например, TDictionary<string, string> это всегда будет один и тот же конкретизированный тип.


Прошу прощения, а можете одним абзацем описать, что такое tdictionary и для чего он используется? Я пока не понял. Это не то же самое, что массив из рекордов, содержащих два поля?
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.
Re[3]: Generics под капотом
От: rudzuk  
Дата: 22.01.23 19:49
Оценка: 2 (1)
Здравствуйте, Khimik, Вы писали:

K> Прошу прощения, а можете одним абзацем описать, что такое tdictionary и для чего он используется? Я пока не понял. Это не то же самое, что массив из рекордов, содержащих два поля?


Ассоциативный массив это. Реализован в виде хэш-таблицы с открытой адресацией.
avalon/3.0.2
Re: Generics под капотом
От: Aquilaware  
Дата: 23.01.23 19:56
Оценка:
Здравствуйте, swame, Вы писали:

S>bds.exe доходит до предела 3Гб


Очевидный вариант — это просто доставить ОЗУ в машины. 3 Гб по нынешним меркам это не очень много. Сейчас разработчику нужно >= 16 Гб ОЗУ чтобы более или менее себя комфортно чувствовать с современным ПО.
Re[2]: Generics под капотом
От: rudzuk  
Дата: 23.01.23 21:17
Оценка: +1
Здравствуйте, Aquilaware, Вы писали:

A> S>bds.exe доходит до предела 3Гб


A> Очевидный вариант — это просто доставить ОЗУ в машины. 3 Гб по нынешним меркам это не очень много.


bds.exe 32-битный процесс, он больше 4GB (адресного пространства!) не съест.

A> Сейчас разработчику нужно >= 16 Гб ОЗУ чтобы более или менее себя комфортно чувствовать с современным ПО.


Менеджед ПО — зло.
avalon/3.0.2
Re[5]: Generics под капотом
От: Mr.Delphist  
Дата: 24.01.23 11:24
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>За 13 лет прошедших с выхода Delphi 2010 ничего не изменилось...


Воспоминания, воспоминания...
Delphi 5, проект 300к строк компилировался нормально, но в конце иногда сдыхал линкер. Поменяли на линкер от Delphi 2005 — проблема ушла.
Вывод — надо просто подождать
Re[3]: Generics под капотом
От: Mr.Delphist  
Дата: 24.01.23 11:29
Оценка:
Здравствуйте, rudzuk, Вы писали:

R>Здравствуйте, Aquilaware, Вы писали:


A>> Сейчас разработчику нужно >= 16 Гб ОЗУ чтобы более или менее себя комфортно чувствовать с современным ПО.


R>Менеджед ПО — зло.


При чём тут managed или нет? Всё от задач засисит. Вот у меня сейчас ноут 16 гиг, всё более-менее норм. Но если запустить докер с виртуалкой какой-нибудь, а-ля Ubuntu с кубернетисами, то ой, RAM прямо по верхней границе колеблется. Потому как вроде бы не слишком большие аппетиты каждого из инструментов суммируются в заметную цифру.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.