线程安全,异步和简单的消息传递系统,用于IPUB团队创建的Delphi类 /层之间的交流。
Delphi拥有自己的消息传递系统(System.Messaging.PAS),可正常工作,但完全同步并且线程不安全。在多线程系统中,我们始终需要与其他类进行通信,有时是同步的,有时异步的,有时会与Mainthread(在UI的情况下)同步,并且在没有消息系统的情况下进行此操作(直接直接通信)使代码大而复杂,易于许多错误。
理想的消息传递系统将是一个线程安全系统,该系统将允许类订阅,然后在这段时间内取消订阅来收听特定消息,而将接收到消息的侦听器类是谁将告知发件人如何调用其方法:在同一线程(发布),在主线程( MAIN )上,在另一个线程( async )和其他主线(MAIN)和其他主(背景)。这是我们的消息传递系统的基础,使用情况类似于另一个现有系统Delphi Event Bus(DEB)。
请参阅具有1000个对象的环境中的比较:
| 订阅 | 邮政 | 退订 | |
|---|---|---|---|
| IPUB | 1.6368毫秒 | 0.1215 ms | 1.7666 ms |
| Deb | 9.8832 ms | 2.0293 ms | 4.0022毫秒 |
ILogOutMessage = interface
[ ' {CA101646-B801-433D-B31A-ADF7F31AC59E} ' ]
// here you can put any data
end ;首先,您必须订阅班级以收听消息,然后将订阅具有[subscribe]属性的所有公共方法。
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,vcppublic,vcpublic,vcpublic)]})}。
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);这两种手动方法与订阅 /退订方法无关。您可以使用[subscribe]属性自动将同一类与订阅方法合并,并调用subscribe / nisberscribe,与此同时,在此类的同时,使用sisscribemethod / unsemethod / unsubScribemeThod手动添加的方法。
手动注册方法的另一个好处是,它们不仅限于公共方法(尽管可以使用RTTI显式方法指令解决此问题)。
系统的想法仅是为了转发消息,通知,包含信息或不信息,因此请记住,不建议将大型代码或代码放置在订阅的方法中以聆听消息的方式,因为这将直接影响系统的性能,即使以异端模式下也会影响系统的性能。
另一个考虑因素只是提醒使用Delphi的TTASK的正确方法。切勿使用TTASK执行停止(事件,信号量,...),它不是为此而进行的,其目标是执行连续,更简单的任务,如果您的任务更为复杂,正确的方法是使用tthread。我们正在警告您,因为我们的系统使用Delphi的TTASK来提高性能,主要在更复杂的环境中除了节省资源之外,如果您在代码中不正确地使用ttask,则在发送消息时可能会导致应用程序冻结。
IPUB消息传递在MIT下许可,并且该文件夹中包含许可证文件。