Forum Replies Created
-
AuthorPosts
-
Ruslan_blrParticipant'TCount' wrote:
😆 Предлагаю заканчивать дискуссию) надоело, правда) каждый решает сам, как ему программы писать.
:wacko:
Ruslan_blrParticipant'TCount' wrote:В статье не написано, что это функция. Написано, что вызывается МЕТОД, возвращающий Count. Но Вы не поняли, о чем я говорил, дело не в методах и не в свойствах, а факт того, что лишние вычисления процессор проводит. На Вашем компе это не ощутимо, потому что в его проце как минимум 2 ядра, у меня одноядерный и результаты я Вам показал.
Более того, эксперимент был проведен всего лишь на “b-1”, а не на сложной функции.
Глупо полагать, что в цикле вроде “For a:=0 to b-1 do…” конечный итог вычисляется сразу. Цикл каждый раз вычисляет выражение “b-1”, потому как нигде не хранит в памяти результат выражения “заранее”.
Ruslan_blrParticipant'TCount' wrote:Все правильно написано! Для простых выражений границы цикла вычисляются сразу. Так и написано, но в Вашем случае были неявные границы в цикле, поэтому ничего заранее не вычислялось.
Вы сами-то задумывались, как может вот такое выражение вычислиться заранее и один раз?
B:=1;
FOR a:=0 TO B*2-1 DO BEGIN
B:=a+5;
if A>=1000 then BREAK;
END;
Вынесение инвариантного кода за пределы цикла – не выносится. Наиболее распространенный недочет – условие цикла записывается как:
for i:=0 to memo1.lines.count – 1 do…
Delphi будет при каждой итерации вызывать метод count, вычитать из результата 1 и потом уже сверять. Настоятельно рекомендуется переписывать подобный код как
lin := .lines.count – 1;
for i:=0 to lin do…
Весь код VCL написан с нарушением этого правила. Очевидно, что проще подобного рода оптимизацию встроить в компилятор, нежели переписывать VCL 🙂
Про остальное можно почитать здесь:
в статье про циклы написан БРЕД.
count – это НЕ функция кот. возвращает кол-во , это СВОЙСТВО.
вот кусок кода из System.Classes:
Code:TStrings = class(TPersistent)
protected
…
function GetCount: Integer; virtual; abstract; // виртуальная, абстрактная – реализация в наследнике, т.е. в TStringList, т.к. my_TStrings:= TStringList.Create
…
public
…
property Count: Integer read GetCount;
…TStringList = class(TStrings)
…
protected
…
function GetCount: Integer; override;смотрим ее реализацию
Code:function TStringList.GetCount: Integer;
begin
Result := FCount; // возвращает значение приватного поля, а не подсчитывает кол-во.
end;FCount меняется в функциях типа Add, Delete и т.д.
но это в принципе не очень важно, факт в том, что
Quote:Delphi будет при каждой итерации вызывать метод count, вычитать из результата 1 и потом уже сверятьполный бред. ну проведите же вы эксперименты
Ruslan_blrParticipant'TCount' wrote:А Вы переводили это?
“…в заявлении является то, что в то время как цикл переоценивает finalValue до
каждая итерация. Это может привести к снижению производительности заметно, если finalValue является сложным выражение, и это также означает
что изменения в стоимости finalValue в заявлении может повлиять на выполнение цикла.”
конечно, мы не говорим о сложных конструкциях, но нужно понимать, что финальное значение вычисляется во время цикла постоянно. Возникает вопрос “а нафиг мне нужно это лишние вычисление?”.
пройдите по ссылке и найдите этот текст.
переведу весь блок:
Quote:For purposes of controlling the execution of the loop, the expressions initialValue and finalValue are evaluated only once, before the loop begins. Hence, the for…to statement is almost, but not quite, equivalent to this while construction:Code:begin
counter := initialValue;
while counter <= finalValue do
begin
… {statement};
counter := Succ(counter);
end;
end.The difference between this construction and the for…to statement is that the while loop reevaluates finalValue before each iteration. This can result in noticeably slower performance if finalValue is a complex expression, and it also means that changes to the value of finalValue within statement can affect the execution of the loop.
перевод
Quote:Для целей управления выполнением цикла, выражения InitialValue и finalValue оцениваются только один раз, перед началом цикла.Таким образом, конструкция for..to почти, но не совсем, эквивалентна этой конструкции while:
Code:begin
counter := initialValue;
while counter <= finalValue do
begin
… {statement};
counter := Succ(counter);
end;
end.Разница между этой конструкции и конструкцией for..to является то, что цикл while переоценивает finalValue перед каждой итерации. Это может привести к заметно более низкой производительности, если finalValue является сложным выражением, и это также означает, что изменения значения finalValue в выражении может повлиять на выполнение цикла.
а теперь осмыслите то, что я написал.
Quote:А у меня результаты:1139
1658
я думаю эта разница в примерно 500 тиков уходит на одноразовое вычисление значения конечного значения счетчика цикла (b-1)
сделайте так
Code:procedure Test;
var
i, j: Cardinal;
a, b : Integer;
begin
i:= GetTickCount;
b:= 1000000000;
for a := 0 to b do
begin
if (a=0) then i:= GetTickCount; // в кол-ве тиков не будет значения, затраченного на выч-е конечного значения счетчика циклаend;
j:= GetTickCount – i;
ShowMessage( IntToStr( j ) );b:= 1000000001;
for a := 0 to b-1 do
begin
if (a=0) then i:= GetTickCount;end;
j:= GetTickCount – i;
ShowMessage( IntToStr( j ) );
end;
как не парадоксально, но
выполняя 1-ый раз
1969 и 1938,
а 2-й
1938 и 1984.
я думаю тут точно не вычислишь, т.к. особенности реализации GetTickCount
Ruslan_blrParticipantемае я в шоке с Вас.. серьезно… я уже было начал сомневаться в своей адекватности …) проведите у себя эксперимент )))
Code:var
i, j: Cardinal;
a, b : Integer;
begin
i:= GetTickCount;
b:= 1000000000;
for a := 0 to b do
beginend;
j:= GetTickCount – i;
ShowMessage( IntToStr( j ) );i:= GetTickCount;
b:= 1000000001;
for a := 0 to b-1 do
beginend;
j:= GetTickCount – i;
ShowMessage( IntToStr( j ) );
end;
результаты будут одинаковыми. у меня например 1688 И 1688. Это ж блин основы программирования.
или например так
Code:var
a: Integer;st: TStrings;
begin
st:= TStringList.Create;
st.Add('a');
st.Add('b');
st.Add('c');
st.Add('d');
st.Add('e');
st.Add('f');
st.Add('g');
st.Add('h');// count = 8
for a := 0 to st.Count-1 do // цикл идет до 7-ми
begin
ShowMessage( st.Strings[a] );if a = 2 then st.Delete(a); // удалил элемент. count = 7
end;
// на последнем шаге (a=7, но не как не st.Count-1, т.е 6 ) вывалится Exception class EStringListError with message 'List index out of bounds (7)'.end
еще нужны доказательства ?
Ruslan_blrParticipant'TCount' wrote:Как раз я и прав)
1. b:=10000;For a:=0 to b-1 do…
2. b:=9999;For a:=0 to b do…
Как думаете, что быстрее? Смысл не в том, когда цикл прерывается, а вообще в логике построения.
Этот форум для абсолютно всех и все могут отвечать на те или иные вопросы. Просмотрите форум, не думаете же Вы, что на все вопросы отвечает поддержка?)
Когда отвечает поддержка, то и ник у нее соответствующий)
подтвержу документально. вот выдержка из офф. доки ембаркадеро ( http://docwiki.embarcadero.com/RADStudio/XE5/en/Declarations_and_Statements)
For purposes of controlling the execution of the loop, the expressions initialValue and finalValue are evaluated only
once, before the loop begins.
The difference between this construction and the for… to statement is that the while loop reevaluates finalValue before
each iteration. This can result in noticeably slower performance if finalValue is a complex expression, and it also means
that changes to the value of finalValue within statement can affect the execution of the loop.
Ruslan_blrParticipant'TCount' wrote:В конструкции типа “for I := 0 to TitleBar_Main.Items.Count-1 do” каждый шаг переменной I вычисляется значение “TitleBar_Main.Items.Count-1”, а это лишняя операция, особенно если итемов много.
Вы не правы ! в моей процедуре закомменте Break и после if then begin … end поставьте например if i=2 then TitleBar_Main.Items.Delete(i); count естестно уменьшится на -1 а цикл пойдет до конца и на последней итерации будет Argument out of range. считайте,что конечное зн-е счетчика цикла это константа и оно высчитывается только ОДИН РАЗ перед первой итерацией. это ж азы ёмаё )).
а по поводу вылета… если это вопрос к разработчику, то кто тогда Вы ? смотрящий что-ли ?))
Ruslan_blrParticipant'TCount' wrote:У меня привычка оптимизировать)) В данном случае эта оптимизация не сильно влияет на общий результат, но если использовать ее повсеместно, то результат будет очевиден.
Переменная введена для ускорения работы цикла, но с циклом Repeat..Until было бы еще быстрее (правда, это незаметно). Ну еще в процедуре испольщовано CONST.
а как переменная ускоряет цикл ? конечное значение счетчика цикла вычисляется по-моему на первом шаге. тоесть если в теле цикла например удалить один из айтемов, то на последнем шаге будет что-то типа Index out of bounds. конечное значение счетчика цикла не пересчитывается каждый раз. ну и const..:) вы все по ГОСТу делаете ?)
а по проблеме что скажете ? если компилить под win 8.1 x64 то вылетает.
Ruslan_blrParticipantинтересно получилось…
эти вылеты были на рабочем компе с Win 8.1 x64.
ничего не меняя перекомпилил на домашнем Win7 x64 – и никаких вылетов.
м.б. дело в этом ?
и еще – процедура принадлежит форме ,а конкретнее сеттеру одного из её св-в(перед begin) , и TitleBar создан в дизайн-тайме. так что дело точно не в этом.
и еще – какой смысл в предложенной оптимизации ? зачем заводить лишнюю переменную ?
… только что скомпилил под Win7 x64 и запустил на виртуальке Win8 x64 – вылетов нет.
-
AuthorPosts