Delphi 7 и события - PullRequest
       29

Delphi 7 и события

1 голос
/ 16 декабря 2008

Я исследую ошибку, которая выглядит как какая-то проблема с синхронизацией, и поэтому мне немного любопытно, как события работают в Delphi 7. Что происходит, когда мы получаем некоторые данные, отправляемые в наше приложение через интерфейс COM, и это обрабатывается в событии, вызванном потоком COM. Похоже, событие, в котором содержится немало кода, выполняется все дольше и дольше, и через некоторое время происходит сбой всего приложения. Внутри события есть вызовы графики и вставка больших массивов, которые могут повлиять на время. Я не смог заметить какого-либо значительного увеличения использования памяти и не имел возможности запустить какие-либо профилировщики для проверки на утечки. Кроме того, очевидная вещь, которую можно протестировать, - это удалить событие всего кода в нем, чтобы посмотреть, сможем ли мы работать в течение более длительного периода времени.

Являются ли события в Delphi последовательными или параллельными, то есть, если я получаю новое событие во время его выполнения - что происходит? Он запускается параллельно на каком-то автоматическом потоке, игнорируется или ставится в очередь?

Если он находится в очереди, сколько я могу иметь в очереди до сбоя приложения?

Уходит ли индексация в большой массив дольше, чем дальше? Даже если это фиксированный размер? Я не думаю, что это должно так, поэтому я ищу утечки и распределения, которые занимают время. Если мне отправляют объект через событие, должен ли я избавиться от него в событии или в «вызывающем» коде?

Какие вещи обычно плохо масштабируются в Delphi? Что я могу найти, чтобы увеличить время выполнения?

Наконец, поскольку это связано с COM, любые указания на распространенные ошибки в COM приветствуются, хотя я понимаю, что это сложно. У меня все же есть со-инициализация.

Ответы [ 3 ]

2 голосов
/ 08 июня 2009

Delphi в основном последовательный в обработке событий. К сожалению, можно указать Delphi обрабатывать другие события, когда вы уже выполняете какое-то событие. В результате новые события будут выполняться, пока ваше текущее событие ожидает завершения нового события. В худшем случае может показаться, что ваше приложение ведет себя нормально, в то время как оно действительно суммирует события в событиях внутри событий. Правило первое: избегайте использования Application.ProcessMessages, если вам это действительно не нужно.

При использовании COM-объектов все становится немного сложнее, поскольку COM-объект может иметь свои собственные события, запускать свои собственные потоки и делать все другие виды вещей, над которыми у вас нет никакого контроля. COM, кажется, прост в использовании в Delphi, но он имеет много скрытых ошибок для неопытных разработчиков. (У меня до сих пор остались шрамы после нескольких из них!)

В общем, при работе с COM-объектами я пытаюсь разделить COM-вызовы в их собственных потоках, создавая специальные компоненты, которые будут хранить COM-объект в своем собственном потоке, и добавляя много кода синхронизации, чтобы я мог GUI реагирует, пока какая-то длинная задача COM выполняет некоторую обработку. Но для этого требуется большой опыт работы с COM и многопоточностью. Но в основном, разработка вашего пользовательского компонента-оболочки вокруг любого COM-компонента - это хорошая практика, просто для защиты ресурсов, которые нужны вашему COM-классу.

Самая сильная слабость Delphi - это обработка строк и обработка огромных массивов. (Особенно это касается массивов, которые содержат объекты; вместо них используются записи.) Сами строки в Delphi работают быстро, но строковые функции в Delphi не очень оптимизированы. Например, у меня когда-то была строка, содержащая некоторые данные XML. В нем было много логических полей, которые были написаны как «Истина» и «Ложь» и должны были преобразовать их в «истина» и «ложь». Простая замена строки заняла около 15 секунд, чтобы заменить все эти значения. Я переписал его, используя MSXML для загрузки XML в документ DOM, используя XPath, чтобы выбрать все логические узлы, перебрать эти узлы, чтобы заменить все значения соответствующими текстами, а затем поместить XML обратно в одну строку. Внезапно он смог сделать то же самое в течение двух секунд! Огромная производительность радует чего-то медленного. Причина? Когда Delphi обрабатывает строки, он имеет тенденцию копировать строку несколько раз во время обработки. Или для увеличения размера строки необходимо выделять все больше памяти. Это занимает время, которое не теряется впустую в некоторых других языках, таких как C ++.

0 голосов
/ 10 июня 2009

Для COM важно то, какую «модель квартиры» поддерживает ваше приложение. В Delphi чаще всего используется модель однопотоковой квартиры , также известная как «квартира в потоке», где COM-вызовы синхронизируются с основной очередью сообщений вашего приложения. В этой модели вы сможете обрабатывать только один COM-вызов за раз, а COM-объекты не поддерживают вызовы из других потоков.

Однако вы можете инициализировать модель своей квартиры COM как многопоточную , и при этом вам нужно будет убедиться, что доступ к общим ресурсам правильно синхронизирован - каждый запускаемый вами поток должен будет присоединиться к многопоточной квартире по телефону CoInitializeEx(nil, COINIT_MULTITHREADED);

Вещи становятся действительно интересными, когда вы представляете интерфейсы DCOM, поскольку подсистема RPC имеет пул потоков для обслуживания запросов, который может напрямую обращаться ко всем вашим COM-объектам в многопоточной квартире, обеспечивая высокопроизводительный сервер. Если вы используете многопоточность, вам придется пройти через узкое место в очереди сообщений, и один поток может отправлять только один COM-вызов за раз.

Крис Бенсен тоже написал об этом хороший пост с некоторыми примерами кода.

0 голосов
/ 18 декабря 2008

Провел некоторое исследование и получил несколько советов, особенно на мой первый вопрос:

Являются ли события в Delphi последовательными или параллельными, то есть, если я получаю новое событие во время его выполнения - что происходит? Он работает параллельно на каком-то автоматическом потоке, игнорируется или ставится в очередь? Если он находится в очереди, сколько я могу иметь в очереди до сбоя приложения?

Ну, очевидно, события такие же синхронные, как и во всем остальном, или, я бы сказал, последовательные. Вы не можете получить больше событий при обработке одного, поскольку это событие по сути является вызовом функции.

В обработчике событий обрабатываются некоторые графические компоненты. Поскольку событие возникает в другом потоке, это плохо. Мне нужно либо сделать какой-нибудь механизм обновления графики, который лежит в потоке, который создал графику, либо сделать переключение потока в событии.

Кроме того, тесты показывают, что на самом деле это обновление графики, которое занимает все больше времени, поэтому рефакторинг обработки графики звучит как хороший путь для начала.

...