Здравствуйте, Shmalex, Вы писали:
S>Вопрос!! S>Допустим естьтакой код S>... S>For i:=1 to 10000000 do begin S>{тута подсчитываем значения} S>end; S>... S>Нак форме валяются кнопки <Страт> и <стоп>. Но во время выполнения цикла, они не сработывают. Нуна чтоб они работали, т.е: S>... S>For i:=1 to 1000000 do begin S>{тута подсчитываем значения} S>{проверка на нажатие кнопки <стоп>} S>end; S>...
Для этого долгую операцию (твой цикл) нужно выносить в другой поток (Thread)
Почитай про TThread
{проверка на нажатие кнопки <стоп>} делается так:
1. Заводим в форме переменную типа Boolean, например FContinue.
2. Перед выполнением цикла выставляем ее в true.
3. В обработчике кнопки Stop выставляем ее в False
4. В цикл добавляем следующие 2 строки:
Application.ProcessMessages;
if not FContinue then break;
5. Когда ты это сделаешь, все начнет страшно тормозить. Потому, что ProcessMessages — операция дорогостоящая. Есть два решения:
а) проверять не на каждой итерации цикла, а, например, через 128 или через 1024:
if (i and 127) = 0
then begin
Application.ProcessMessages;
if not FContinue then break;
end;
б) проверять по времени, а не по итерациям (например, через полсекунды). Код тривиальный.
... << RSDN@Home 1.1.2 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
5. Когда ты это сделаешь, все начнет страшно тормозить. Потому, что
ProcessMessages — операция дорогостоящая.
Метод ProcessMessages не является дорогостоящим, дорогостоищим является
обработка событий если такие будут.
Для проверки создай простой проект с одной меткой и кнопкой, в обработчике
которой напиши такое.
procedure TForm1.Button1Click(Sender: TObject);
var
T: Cardinal;
I: Integer;
begin
T := GetTickCount;
for I := 1 to 1000000 do Application.ProcessMessages;
Label1.Caption := '1 миллион итераций выполнен за ' +
IntToStr(GetTickCount-T) + ' миллисекунд';
end;
for i := 1 to 1000000 do begin{здесь подсчитываем значения}
{проверка на нажатие кнопки <стоп>}if (i mod 100) = 0 then
Application.ProcessMessages;
end;
Условие нужно для того чтобы не вызывать Application.ProcessMessages на каждой итерации (слишком сильно грузит процессор). В приведённом примере вызов производится каждые 100 итераций.
Application.ProcessMessages обрабатывает все пришедшие за время обработки предыдущего блока оконные сообщения, в том числе и клик на той самой кнопке <стоп>.
Здравствуйте, Anatoly Podgoretsky, Вы писали: AP>Метод ProcessMessages не является дорогостоящим, дорогостоищим является AP>обработка событий если такие будут.
Все познается в сравнении
procedure TForm1.Button1Click(Sender: TObject);
var
T: Cardinal;
I: Integer;
k: integer;
begin
T := GetTickCount;
k:=0;
for I := 1 to 10000000 do
begin
k:= k+i;
Application.ProcessMessages;
end;
Label1.Caption := '10 миллионов итераций выполнено за ' +
IntToStr(GetTickCount-T) + ' миллисекунд; результат='+IntToStr(k);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
T: Cardinal;
I: Integer;
k: integer;
begin
T := GetTickCount;
k:=0;
for I := 1 to 10000000 do
begin
k:= k+i;
end;
Label1.Caption := '10 миллионов итераций выполнено за ' +
IntToStr(GetTickCount-T) + ' миллисекунд; результат='+IntToStr(k);
end;
у меня Button1Click выполняется примерно полсекунды. Button2Click выполняется от 15 до 30 миллисекунд. Оптимизации выключены.
... << RSDN@Home 1.1.2 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
"Sinclair" <5743@news.rsdn.ru> сообщил/сообщила в новостях следующее: news:493914@news.rsdn.ru...
From: Sinclair модератор
> у меня Button1Click выполняется примерно полсекунды. Button2Click
выполняется от 15 до 30 миллисекунд. Оптимизации выключены.
Все правильно, это дает нам что издержки на один вызов
Application.ProcessMessages составляют у тебя 50 наносекунд, то есть никакой
речи о гигантской ресурсоемкости, о которой говорилось и речи нет. То есть
на 10 миллионов вызовов мы даже глазом моргнуть не успеваем.
В общем я это дело решил таким образом:
Плюс ко всем компонентам добовляем тамер
Timer1.enabled:=false;
Timer1.Interval:=1;
Запускаем цикл For i:=1 to М do ...
Этот Цикл повторяется k раз [m*k=n раз (n раз это то сколько нам вообще надо)]
Нажимаем на <Старт>
Timer1.Enabled:=True;
В цикле For мы отключаем Таймер.
Затем опять врубаем Таймер, и в нем проверяем
IF m*k<>n then Delati_For
else Timer.Enabled:=false; // *
После выполнения (*) таймер никогда больше не включится, только если опять нажать <Старт>.
Код не сложный и главная цель этой этой мутатени — получить доступ к событиям остальных компанентов нна форме(П: можно нажать на кнопку <Пауза>).
Здравствуйте, Anatoly Podgoretsky, Вы писали:
AP>"Sinclair" <5743@news.rsdn.ru> сообщил/сообщила в новостях следующее: AP>news:493914@news.rsdn.ru... AP>From: Sinclair модератор
>> у меня Button1Click выполняется примерно полсекунды. Button2Click AP>выполняется от 15 до 30 миллисекунд. Оптимизации выключены.
AP>Все правильно, это дает нам что издержки на один вызов AP>Application.ProcessMessages составляют у тебя 50 наносекунд, то есть никакой AP>речи о гигантской ресурсоемкости, о которой говорилось и речи нет. То есть AP>на 10 миллионов вызовов мы даже глазом моргнуть не успеваем.
Это зависит от того, какие сообщения обрабатываются.
Сообщения могут быть вообще говоря любые и их обработка может быть сколь угодно долгой.
Решение с ProcessMessages конечно же будет работать,
но в реальном приложении я бы не стал рекомендовать этот способ.
Лучше все же вынести дорогостоющую операцию в отдельный поток
и использовать к примеру events для того, чтобы попросить поток прервать операцию.
Чем плох Application.ProcessMessages?
Тем, что по ходу выполнения "длинного" цикла могут выполняться
куски когда, о которых разработчик "длинного" цикла вообще и не предполагает.
Контролировать такой код будет гораздо тяжелее, чем выделенный поток.
Представь, что кто-то потом надумает на форму еще таймер навесить...
В общем решение с потоком, если все сделать аккуратно,
будет более предсказуемым и надежным.
Здравствуйте, Forint, Вы писали: F>Странно, что эта светлая мысль содержится только в одном ответе. Совершенно незачем мудрить с сообщениями.
Неопытному человеку сделать корректную реализацию worker thread довольно тяжко, не напоровшись на проблемы с синхронизацией. В то время как применение обсуждаемых методов в большинстве случаев сводится к добавлению пары строк кода, и вполне решает поставленную задачу.
... << RSDN@Home 1.1.2 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Трудно не согласится. Но всё-таки, для данного типа задач, наиболее подходящим решением является применение потоков. В данном конкретном примере понадобиться 1 поток, следовательно, и проблем с синхронизацией не предвидится.
Здравствуйте, Forint, Вы писали:
F>Трудно не согласится. Но всё-таки, для данного типа задач, наиболее подходящим решением является применение потоков. В данном конкретном примере понадобиться 1 поток, следовательно, и проблем с синхронизацией не предвидится.
Ну, один поток в данном примере уже есть. Понадобится второй. Сначала придется думать, как сделать прерывание второго потока по кнопке Stop. Потом захочется иметь Progress Indicator, и окажется что без синхронизации общаться с VCL нельзя... Это все довольно долгая песня.
... << RSDN@Home 1.1.2 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair: S>Ну ты и намудрил. Куда проще было сделать Application.ProcessMessages.
Слухай если тебе не очень лень, вылжи какойто рабочий исхожник с использовванием Application.ProcessMessages хотьябы узнать что эта за хрень такая?
H e l l o, Shmalex!
S> Слухай если тебе не очень лень, вылжи какойто рабочий исхожник с S> использовванием Application.ProcessMessages хотьябы узнать что эта S> за хрень такая?
Тебе уже несколько людей привели примеры с использованием
ProcessMessages.
--
Всего хорошего, Слава. (http://slava.users.otts.ru)
-= Всего после четырех уроков каратэ, Федор уже легко ломал
трехсантиметровую доску одним ударом гипсовой повязки. =-
Здравствуйте, Shmalex, Вы писали: S>Слухай если тебе не очень лень, вылжи какойто рабочий исхожник с использовванием Application.ProcessMessages хотьябы узнать что эта за хрень такая? http://www.rsdn.ru/forum/Message.aspx?mid=493853&only=1
D> for i := 1 to 1000000 do begin
D> {здесь подсчитываем значения}
D> {проверка на нажатие кнопки <стоп>}
D> if (i mod 100) = 0 then
D> Application.ProcessMessages;
D> end;
D>
В целях экономии времени лучше делать (i and 127) = 0