-
> И разве он также не делает realloc?
не на каждое добавление см. Capacity
-
> @!!ex © (12.12.08 12:35) [17]
Ни TList ни TStringList не работают с дин. массивами, у них своя схема. Как раз блоками.
-
> [20] clickmaker © (12.12.08 12:37)
Я видел как сделан TList. :) В [14] об этом написал.
> Или выделять сразу блоками?
Смысла не вижу в данном случае.
-
Ну на самом деле, все зависит от ожидаемого количествоа этих Extern методов. Если не больше 100, можно сразу размерность выделить 100. И не нагружать менеджер Reallocaми
-
> VMcL © (12.12.08 11:43) [12]
Это те 90% кода которые влияют на 1% производительности. Так что конструкция вполне легитимная, сам так делаю. Данный код при регистрации всех функций не будет на современном процессоре и 0.1 мс забирать.
Так что я против premature optimization, которая приводит к шаманской работе программ - то она работает, то нет.
-
> Palladin © (12.12.08 12:41) [23]
Угу, только при подобных оптимизация получится модуль с производительность выше на 5-10% который будет влиять на 0.0001% производительности программы, с читабельностью кода стремящейся к 0%.
Сам говорю по опыту, тоже пробовал ловить проценты производительности там где не надо. Если так уж важна производительность то уд лучше перевести проект на C++ с нормальным компилятором, а не на тормознутом Ынтерпрайзе Delphi. Даже перекомпиляция на современном FPC увеличивает часто производительность в 300%.
Это конечно хорошо для того, кто хочет завязать проект на себя, но плохо для заказчика.
-
> с читабельностью кода стремящейся к 0%.
Хм, а как повредит единоразовое определение размера дин. массива на читабельность кода?
-
> лучше перевести проект на C++ с нормальным компилятором, > а не на тормознутом Ынтерпрайзе Delphi
Зависит от критерия "нормальности". Для меня, компилятор, собирающий среднего размера проект минутами, нормальным не является :). Но, на вкус и цвет... > Сделал классовую обертку(может кому понадобится?).
Мне понадобилось, давно собирался посмотреть, что за зверь такой этот lua, а тут повод появился. Thanks :). Взял на себя смелость внести некоторые изменения в приведенный модуль: [*] Незначительные изменения для совместимости с D2009 (экспериментировал на ней). В частности, string -> AnsiString, там где нужно. [+] Добавил "Adapter" делфевых объектов. В двух словах, теперь можно легко написать функцию, которая будет возвращать указатель на объект вовнутрь lua в виде user_data. Операции над ним перекрыты с помощью т.н. метатаблиц. Луа скрипт выглядит так: local obj = trygetobject()
local name = obj.Name
obj.Name = "I was "..name.." some day, but i got NAME now!"
for i=1,10 do
obj.Size = obj.Size + 1
end и он рулит объектом, описанным так:
TMyObj = class(TObject)
private
FName: string;
FSize: Integer;
procedure SetName(const Value: string);
procedure SetSize(const Value: Integer);
published
property Size: Integer read FSize write SetSize;
property Name: string read FName write SetName;
constructor Create; virtual;
end;
Если у кого-нибудь есть идеи, как разрулить вызов методов из lua кода, был бы счастлив их услышать. Да, измененный модуль (с примером использования) лежит тут: http://slil.ru/26429923
-
Забыл добавить, размер архива по ссылке 174 Кб.
-
>>Городской Шаман (12.12.08 13:58) [24]
У каждого свои тараканы. Мои позволяют, единожды написав и протестировав код, возвращаться к нему только для добавления новой функциональности.
-
> Palladin © (12.12.08 14:12) [26] > > > > с читабельностью кода стремящейся к 0%. > > Хм, а как повредит единоразовое определение размера дин. > массива на читабельность кода?
Тем что в данном случае указатели на обработчики lua функций добавляются в динамике и для разных проблемных областей там может быть разное количество, а здесь нужно шаманить со статикой и пользователю компонента знать как он устроен внутри
Кроме того если Delphi уж берёт на "магию компилятора" динамические массивы то и компилятор должен заботится и о выделении памяти блоками под него.
Во множестве реализаций std::vector выделяется память для динамического массива блоками определенной длинны и именно разработчик библиотеки берет на себя ответственность за распределение памяти внутри.
А если компилятор при вызове Setlength(,+1) каждый раз перераспределяет память, то это кривой компилятор.
-
> А если компилятор при вызове Setlength(,+1) каждый раз перераспределяет > память, то это кривой компилятор.
Компилятор ничего не перераспределяет, он всего-лишь вставляет туда вызов соответствующей функции менеджера памяти. А менеджер памяти, если я правильно помню, можно заменить. Вроде как, именно это делал FastMM, недавно мелькало обсуждение.
В общем-то, спор ни о чем. Смысла оптимизировать при количестве добавляемых функций порядка 10-1000 по-видимому нет (добавление единократное, так как функции удаления из списка нет ^_^). С другой стороны, наличие такой оптимизации, тоже ничем не помешает (сложность кода повысится уж очень незначительно, говорить о нечитабельности или большой вероятности допустить там ошибку - преувеличение). Так что, пускай каждый и дальше делает, как ему нравится.
-
> VMcL © (12.12.08 14:38) [29] > > >>Городской Шаман (12.12.08 13:58) [24] > > У каждого свои тараканы. > Мои позволяют, единожды написав и протестировав код, возвращаться > к нему только для добавления новой функциональности.
Тогда зачем нам Delphi давайте бухгалтерские программы писать сразу на assembler с использованием SSE и CUDA для повышения производительности.
-
> Городской Шаман (12.12.08 14:59) [32]
Во всем есть здравый смысл. Давай рассмотрим конкретно эту ситуацию.
1. Это библиотечный кот. Поэтому для данного кота вопрос оптимизации имеет большую роль в силу так называемого экспоненциального взрыва.
2. Скорость работы алгоритма зависит от длины массива. Предположим достаточно типичную ситуацию, что нам надо добавить 10 000 методов. В самом печальном случае на это потребуется примерно столько же релокаций памяти плюс копирование. Опять, отбрасывая копейки, средний размер массива 40 000 * 0.5 байт = 20 000 байт, умножая на 10 000 релокаций получаем копирование 200 Mb. Конечно, менеджер памяти у Delphi хороший, и не всякая релокация будет связана с копированием. В .NET это может оказаться более фатальным. Если там не предусмотрено специальных оптимизаций, то может понадобится 10 000 выделений памяти, несколько запусков сборщика мусора, а также копирование всего заявленного объема.
3. Если в данном случае использовать TStringList, код станет и короче, и понятнее. Но даже если и самому ввести дополнительную переменную и добавить условие, то это не никоим образом не сделает программу шаманской.
-
> [33] Mystic © (12.12.08 15:37)
Lua скрипт с 10 000 глобальных методов сдохнет сам по себе, независимо от реаллока.
-
А чего ему сдыхать? Никто не говорит о том, что все эти методы будут вызываться.
-
> [35] Mystic © (12.12.08 15:53)
Обращение к функции идет через вызов метода lua_getglobal. Это перебор всех глобальных значений с сравнением строк. Для каждого вызова lua_getglobal в среднем нужно 5000 переборов. конечно там не используется явный перебор и явное сравнение строк, что позволяет чуть ускорить это дело. Но суть не меняется. Такое количество глобальных значений будет зверско тормозить. Тем более, что в глобальном пространстве хрянятся не только внешние функции, но и множество внутренних данных, которые работают через тот-же lua_getglobal. Так что это будет тормозить не только при вызове функций С из луа, но и при внутренних вызовах функций и переменных.
Опять же пример оторван от жизни. 10 000 внешних функций... Зачем? ВСе взаимодействие обычно происходит через два десятка функций. Как правило при реализации стараются избежать частого вызова lua функций из кода и наоборот.
Оптимизацию такого плана считаю глупой. Оптимизировать надо там, где тормозит. Или где, хотя бы теоретически, может тормозить. ЗДесь не может тормозить даже теоретически. Потому что при достижении большого количества методов возникнут тормоза в других точках, и значительно более серьезные.
-
> Mystic © (12.12.08 15:37) [33]
По поводу (2) тогда стоит стоит добавить отдельный метод AddMethodList(array of ...) который и будет добавлять уже сформированный массив у "клиентского кода" из 10000 методов.
И вся проблема. Но второй метод если у будет использоваться, то только в 0.0001% случаев.
-
> Mystic © (12.12.08 15:37) [33]
С другой стороны - 10000 методов, да в WinApi поменьше функций будет.
Если 10000 методов то нужно не lua, а Java + Rhino JavaScript + мейнфрейм за 10000000$.
-
> Городской Шаман (12.12.08 16:15) [37]
Можно добавить и такой метод. Но если изначально размер списка методов установить равных 128, а при исчерпании лимита увеличивать размер ровно в два раза, то нам понадобится семь релокаций, при этом памяти будет скопировано ~ 100 кб, что всего в два с половиной раза больше первоначального размера списка. Разницы между твоим оптимизированным методом AddMethodList и добавлением методов в цикле никто и не заметит. Тем более, что этот массив, который передается в качестве аргумента, также надо будет сформировать. Очень может быть, что он читается из файла, и нам заранее неизвестно сколько в нем элементов. История повторяется :)
> Городской Шаман (12.12.08 16:18) [38]
Конечно, если писать совсем не задумываясь об оптимизации, то никаких денег не хватит :) Вопрос еще и в том, что всякий раз, когда мне нужно добавить элемент к массиву, мне надо думать, к чему это приведет. Не проще ли забыть об этим потенциальных граблях и приучить себя писать дополнительные пару строк кода? А в случае TStringList и вовсе удалить пару строк. Ведь обходится большинство потенциальных проблем, а усилий никаких.
|