Блог. Двадцать пять лет Делфи-практики
В этом блоге я буду публиковать ответы на вопросы, которые постоянно приходится повторять на форуме.
Здесь можно это сделать более развернуто и спокойно.
Все, что здесь написано, не является истиной в последней инстанции, скорее, это результат моих размышлений над архитектурой проектов, маленьких и больших, которых я сделал на Делфи более дюжины.
Начав с Делфи-2 двадцать пять лет назад, я прошел все версии, испробовал массу технологий, включая работу с БД, с графикой DirectX, связью с серверами и интернетом, разработку на Андроид и IOS, и многое, многое другое.
________________________________________ ________________________________________ ____
P.S. все, о чем здесь написано, всего лишь измышления из головы.
совпадения с реальными людьми и фактами случайны.
В этом блоге я буду публиковать ответы на вопросы, которые постоянно приходится повторять на форуме.
Здесь можно это сделать более развернуто и спокойно.
Все, что здесь написано, не является истиной в последней инстанции, скорее, это результат моих размышлений над архитектурой проектов, маленьких и больших, которых я сделал на Делфи более дюжины.
Начав с Делфи-2 двадцать пять лет назад, я прошел все версии, испробовал массу технологий, включая работу с БД, с графикой DirectX, связью с серверами и интернетом, разработку на Андроид и IOS, и многое, многое другое.
________________________________________ ________________________________________ ____
P.S. все, о чем здесь написано, всего лишь измышления из головы.
совпадения с реальными людьми и фактами случайны.
ProcessMessages
Запись от krapotkin размещена 30.08.2017 в 06:54
Показов 13446
Комментарии 9
Метки delphi
|
Как только я вижу в чьем-то коде Application.ProcessMessages, я сразу вспоминаю - несчастные случаи на стройке Поясню: Вся программа на делфи выглядит примерно так
Сообщений сотни - каждое движение мыши, таймеры, перерисовка окантовки и заголовка окон, вообще все в Windows делается по сообщениям. И вот при обработке сообщения программа вызывает ваш обработчик события. Например, нажатия кнопки. А там вы делаете что-то очень важное для вас и хуже всего - длительное по времени. И тут встает проблема. Перерисовка окна и обработка ввода идут тоже через сообщения, а программа еще не вышла из вашего обработчика и никаких сообщений не обрабатывает, и все говорят - висит! Да нет, не висит, вы сами ее чем-то заняли, она работает. Чаще всего в к-нить вашем цикле, или качает что-то из интернета. И для простого решения проблемы "зависания" программист пишет Application.ProcessMessages! И вуаля - программа перерисовывает окно и даже вызывает еще какой-то обработчик мыши. И тут начинаются спецэффекты Напоминаю. Ваш обработчик вызван из какой-то процедуры компонента, которая по цепочке вызвана из обработчика события Application.ProcessMessages. И вы тоже вызываете ProcessMessages. Да еще в цикле! Получится ProcessMessages -- Обработчик сообщения -- Процедуры объектов -- Ваш обработчик -- ProcessMessages -- Обработчик сообщения -- Процедуры объектов -- ???? и вот тут запросто может быть заново вызван ваш обработчик опять!!! И дальше все по кругу... Либо как вариант, компонент может полагаться на последовательные вызовы событий типа OnCreate -- OnShow -- OnActivate а тут еще Create не закончился, а уже Show. oO Программа становится НЕЛИНЕЙНОЙ! В нормальном состоянии ваши процедуры отрабатывают друг за другом, от начала и до конца. Никаких параллельностей. Тут же это не так! Следующие процедуры запросто вызываются, когда еще не закончилась текущая. А потом текущая продолжится! Конечно, не всегда это приводит к печальным последствиям, но делать так НЕ СТОИТ! А если сделали, не удивляйтесь! Иногда вместо ProcessMessages достаточно просто перерисовать компонент Component1.Update; Иногда длительное действие нужно вынести в отдельный поток. С потоками решение сложной задачи можно разбить на два этапа - старт задачи и, отдельно - получение результата, когда задача завершилась. Тогда программа может заниматься своими делами, когда расчет (или загрузка файла или...) будет закончен, вызовется обработчик, где вы решите, что делать с результатом. Решения есть. Не ленитесь. И перестаньте вставлять Application.ProcessMessages. P.S. Один из самых клевых результатов даёт нажатие на крестик Закрыть программу. И программа уже думает, что всё - уничтожает формы и данные, а ваш обработчик продолжает обращаться к этим формам и данным, ессно получая AV. Никаких ошибок - просто так задумано вами - программистом. | ||||||||||
Метки delphi
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 9
Комментарии
-
Запись от Rius размещена 30.08.2017 в 07:14
-
Запись от Avazart размещена 30.08.2017 в 12:58
-
Запись от krapotkin размещена 30.08.2017 в 13:33
-
С отдельным потоком дров можно наломать ещё больше. Тут есть дополнительные нюансы типа необходимости использования критических секций (иногда), проблемы взаимодействия с VCL (хотя значения из компонентов нужно читать заранее, а не из цикла). Да и так же, как и при использовании ProcessMessages, нужно отключать кнопки повторного запуска события (и другие сопутствующие) + обрабатывать CloseQuery (нужно же обрывать цикл потока через глобальную переменную или event [TThread.Terminate опасно, если FreeOnTerminate = True] и потом ещё ждать завершения потока)
Другое дело, что дополнительный поток не будет "отвлекаться" на ProcessMessages и может отработать быстрее + (если ProcessMessages вызывается не на каждой итерации, а раз в секунду, скажем) не будет мелких "провисов"...
Но будет не менее прикольно, когда закрытие формы завершит поток фактически через TerminateThread (в момент ExitProcess). И форма ведь закроется (*), и не будет AV, что создаст иллюзию, что код написан верно. Ещё будет забавно новичку искать ошибку, если иногда вдруг (скажем, раз в 10 запусков) будут возникать AV при закрытии формы. Например, когда поток будет обращаться к уже освободившемуся объекту.
Вывод такой: любым инструментом нужно уметь правильно пользоваться. А просто сказать новичку: юзай потоки вместо ProcessMessages тоже не вариант...
p.s.
(*) А вот при цикле с ProcessMessages форма не закроется, тут вы ошибаетесь, программа не даст ей закрыться при нажатии на крестик (или при вызове Close), если только вы не открыли её через Show (без "Modal"), но и в этом случае она не уничтожится, а просто уйдёт в Hide.Запись от Jin X размещена 09.07.2018 в 22:47
-
Запись от Avazart размещена 09.07.2018 в 23:01
-
Запись от Jin X размещена 09.07.2018 в 23:04
-
Новичкам это не грозит, т.к. никто из них не понимает очереди сообщений и непредусмотренного поведения от ProcessMessages.
В справке Embarcadero даже ни слова нет о возможных проблемах, типа юзайте и будет вам счастье, вот же в простеньком "Hello World" всё наглядно показано. В Net Framework же предупреждают:
В сложной программе это источник адовых багов, которые замаешься отлавливать, что в общем и есть говнокод.
Поэтому заранее надо учить правильным методам, а не костылям.
Для новичков - признак движения к мастерству.Запись от Rius размещена 10.07.2018 в 05:58
-
Запись от krapotkin размещена 10.07.2018 в 06:21
-
Не будет, а если и будет то через ... одним словом гавнокод
Но именно так и есть.
В данном случае ProcessMessages не инструмент.
ProcessMessages в коде следствие непонимание этого факта и оправдание что бы и далее не изучать многопоточность.
Думаю есть случаи когда ProcessMessages уместен, но этих случаев очень мало, и большая часть из них банальная лень писать код по нормальному.Запись от Avazart размещена 10.07.2018 в 23:03




