Безопасная тема, асинхронная и упрощенная система обмена сообщениями для связи между классами / слоями в Delphi, созданной командой IPUB.
У Delphi есть своя собственная система обмена сообщениями (System.messaging.pas), которая работает хорошо, но является абсолютно синхронной и небезопасной. В многопоточных системах нам всегда нужно общаться с другими классами, иногда синхронно, иногда асинхронно, иногда синхронизируясь с основной отделкой (в случае пользовательского интерфейса) и выполнять это без системы сообщений (напрямую общение) делает код большим и сложным, подверженным многим ошибкам.
Идеальной системой обмена сообщениями была бы безопасная система, которая позволит классу подписаться, а затем отписаться на прослушивание конкретного сообщения в течение этого времени, и этот класс слушателей, который получает сообщение, кто сообщит, как отправитель будет вызывать свой метод: на той же потоке ( публикации ), в основной потоке ( основной ), в другой потоке ( Async ) и на потоке, кроме основного ( фонового ). Это основа нашей системы обмена сообщениями, использование аналогично другой существующей системе, автобусе Delphi Event Bus (DEB).
Смотрите сравнение в среде с 1000 объектами:
| Подписаться | Почта | Отписаться | |
|---|---|---|---|
| пульт | 1,6368 мс | 0,1215 мс | 1,7666 мс |
| Деб | 9.8832 мс | 2.0293 мс | 4,0022 мс |
ILogOutMessage = interface
[ ' {CA101646-B801-433D-B31A-ADF7F31AC59E} ' ]
// here you can put any data
end ;Во -первых, вы должны подписаться на свой класс на прослушивание сообщений, а затем будут подписаны все публичные методы, которые имеют атрибут [подписки].
TForm1 = class (TForm)
procedure FormCreate (Sender: TObject);
procedure FormDestroy (Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
[Subscribe(TipMessagingThread.Main)]
procedure OnLogout ( const AMessage: ILogOutMessage);
end ;
...
procedure TForm1.FormCreate (Sender: TObject);
begin
GMessaging.Subscribe(Self);
end ;
procedure TForm1.FormDestroy (Sender: TObject);
begin
GMessaging.Unsubscribe(Self);
end ;
procedure TForm1.OnLogout ( const AMessage: ILogOutMessage);
begin
Showmessage( ' Log out! ' );
end ;Вы также можете объявить метод в защищенной части, но для этого необходимо добавить явные методы {$ rtti ([vcprotected, vcpublic, vcpublished])}} до класса.
var
LMessage: ILogOutMessage
begin
LMessage := TLogOutMessage.Create;
GMessaging.Post(LMessage);В предыдущих примерах мы показали интерфейсное сообщение, но есть всего 3 типа сообщений:
| Личность | Параметр |
|---|---|
| имя (явное) | нить |
| GUID интерфейса параметров (неявно) | интерфейс |
| GUID интерфейса параметров (неявное) + Имя (явное) | интерфейс |
Чтобы получить сообщения с идентификацией имени, просто объявьте имя в атрибуте метода:
[Subscribe( ' Name ' , TipMessagingThread.Main)]Чтобы отправить сообщения с идентификацией имени, просто сообщите об этом в сообщении:
GMessaging.Post( ' Name ' , LMessage);Примечание: явное имя нечувствительно.
В атрибуте [подписки] вы можете определить, как будет выполнен метод получения сообщения:
| Добрый | Описание |
|---|---|
| TipMessagingThread.posting | По умолчанию метод подписчика будет вызван в том же потоке публикации, где был вызван сообщение |
| TipMessagingThread.main | Метод подписчика будет вызван в основном потоке |
| TipMessagingThread.Async | Метод подписчика будет вызван асинхронно в новой амонониме, кроме потока публикации |
| TipMessagingThread.background | Если поток публикации является основным потоком, метод подписчика будет вызван асинхронно в новой амонониме, кроме потока публикации. Если поток публикации не является основным потоком, метод подписчика будет вызван синхронно в одном и том же потоке публикации |
Хотя использование атрибута [подписки] для подписки на метод очень практично, оно ограничено, потому что вы должны определить имя сообщения перед компиляцией, во время дизайна, а иногда действительно полезно определить имя сообщений во время выполнения. Пример, сообщение для продукта, который был изменен 'product_105346_changed', это имя этого сообщения, которое я могу определить только во время выполнения, поэтому мы добавили опцию, чтобы подписаться / отписать метод для прослушивания сообщения вручную:
GMessaging.SubscribeMethod<string>( ' product_105346_changed ' , Self.OnProductChanged, TipMessagingThread.Posting);
GMessaging.UnsubscribeMethod<string>( ' product_105346_changed ' , Self.OnProductChanged);Эти два ручных метода не зависят от методов подписки / отказа от подписки. Вы можете объединить один и тот же класс с помощью подписанных методов, автоматически с использованием атрибута [подписки] и вызова подписки / отмены подписки, и в то же время в этом классе, которые вы добавляли вручную, используя подписку -подписание / Unsubscribemethod.
Другое преимущество методов вручную регистрируется, что они не ограничиваются только публичными методами (хотя эта проблема может быть решена с использованием директивы явных методов RTTI).
Идея системы состоит в том, чтобы просто направлять сообщения, уведомления, содержащие или не информацию, поэтому имейте в виду, что не рекомендуется размещать большие коды или коды с остановками (Waitfor) в подписанные методы для прослушивания сообщений, так как это напрямую повлияет на производительность системы, даже в асинхронных модах.
Другое соображение - это просто напоминание о правильном способе использования TTASK Delphi. Никогда не используйте TTASK для выполнения методов с остановками (события, семафоры, ...), это не было сделано для этого, его цель - выполнять непрерывные и более простые задачи, если ваша задача является более сложной, то правильная вещь - использовать Tthread. Мы предупреждаем вас об этом, потому что наша система использует TTASK Delphi для повышения производительности в основном в более сложных средах в дополнение к сохранению ресурсов, и если вы неправильно используете TTASK в кодах, вы можете привести к замораживанию вашего приложения при отправке сообщения.
Обмен сообщениями IPUB лицензируется в соответствии с MIT, а файл лицензии включен в эту папку.