Delphi Event Bus進階(一)控制訂閱方法的線程模式


上文根據Delphi Event Bus開源項目自帶的例子,對其基本用法做了介紹,相信通過這個例子,你也能明白如何使用Delphi Event Bus到自己的項目中,讓項目代碼更解耦,易維護與易擴展。

今天,進一步說說如何更深入的使用Delphi Event Bus。

首先,想說的是對於訂閱方法的注解,如何定義當他執行時,用什么樣的線程。

當我們用[Subscribe]定義一個訂閱方法時,這個方法是在主線程中執行,還是在單獨的線程中執行?這一點對於我們來說,是必須要清晰的。看下面的代碼:

    [Subscribe]
    procedure ReceiveFrameNotification(AEvent:IFrameNotifyMainEvent);

這里,我們要知道[Subscribe]還能用TThreadMode進一步注解,等明白了如何使用TThreadMode,才能正確回答上面的問題。接下來,看一下TThreadMode的定義:

  /// <summary>
  ///   Thead mode of the subscriber method.
  ///  訂閱方法的線程模式
  /// </summary>
  TThreadMode = (
    /// <summary>
    ///   The subscriber method will be invoked in the same posting thread where
    ///   IEventBus.Post is called.
    /// 訂閱方法將在IEventBus.Post時的線程中執行,如果在主線程中Post,那么訂閱方法就在主線程中執行,如果在子線程中執行,那么訂閱方法就在這個子線程中執行。
    /// </summary>
    Posting,

    /// <summary>
    ///   The subscriber method will be invoked in the main thread.
    ///訂閱方法在主線程中執行
    /// </summary>
    Main,

    /// <summary>
    ///   The subscriber method will be invoked asynchronously in a new thread
    ///   other than the posting thread.
    ///訂閱方法將在新的子線程中執行
    /// </summary>
    Async,

    /// <summary>
    ///   If the posting thread is the main thread, the subscriber method will
    ///   be invoked asynchronously in a new thread other than the posting
    ///   thread. If the posting thread is NOT the main thread, the subscriber
    ///   method will be invoked synchronously in the same posting thread.
    ///保證在子線程中執行,如果在主線程中Post,那么訂閱方法將在一個新的子線程中執行,如果Post在子線程中調用,那么訂閱方法將和Post所在的線程中執行。
    /// </summary>
    Background
  );

根據作者的源代碼中注釋做了翻譯,默認情況下,[Subscribe]線程模式為TThread.Posting,也就是在post時所在的線程中執行。現在你可以回答上面的問題了。那如何定義[Subscribe]的線程模式呢?象下面這樣,讓ReceiveFrameNotification在主線程中執行:

    [Subscribe(TThreadMode.Main)]
    procedure ReceiveFrameNotification(AEvent:IFrameNotifyMainEvent);

出差路上,要下車了,現到這里。

繼續補充上面的內容,也是經驗之談,走過的彎路。

如果對上面的說法你還是不清楚,那參考源碼能有助於理解,當你Post完消息后,是執行這個方法TEventBus.PostToSubscription,在這個方法中執行具體的訂閱方法。

procedure TEventBus.PostToSubscription(ASubscription: TSubscription; const AEvent: IInterface; AIsMainThread: Boolean);
var
  LProc: TProc;
begin
  LProc := procedure begin
                          InvokeSubscriber(ASubscription, [AEvent as TObject]);
                     end;//根據ASubscription取得訂閱方法

  case ASubscription.SubscriberMethod.ThreadMode of//根據訂閱方法設置的線程類型來執行訂閱方法
    Posting:
      LProc();
    Main:
      if (AIsMainThread) then
        LProc()
      else
        TThread.Queue(nil, TThreadProcedure(LProc));
    Background:
      if (AIsMainThread) then
        TTask.Run(LProc)
      else
        LProc();
    Async:
      TTask.Run(LProc);
  else
    raise Exception.Create('Unknown thread mode');
  end;
end;

在實際項目中,我們要怎么控制線程模式呢?原則就是你要保證,你自己清楚的知道,發布一個消息時,即執行Post時,收到消息的訂閱方法是在主線程中執行還是在子線程中執行,說到這里,我最討厭的就是只使用[Subscribe],而不是明確的定義一個訂閱方法的線程模式。換句話說,我們不要輕易使用默認值TThreadMode.Posting來定義。確切的說,要么用TThreadMode.Main來定義一個訂閱方法在主線程中執行,要么用TThreadMode.ASync定義一個訂閱方法在子線程中執行,即異步執行。

重復代表重要:當你發布(Post)一個消息,你要清楚的知道接收者是在主線程還是在子線程中執行,或者說是同步執行還是異步執行!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM