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 и для чего он используется? Я пока не понял. Это не то же самое, что массив из рекордов, содержащих два поля?
http://files.rsdn.org/77557/rocksm.png
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...
Пока на собственное сообщение не было ответов, его можно удалить.