• 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)一个消息,你要清楚的知道接收者是在主线程还是在子线程中执行,或者说是同步执行还是异步执行!

  • 相关阅读:
    django-搭建BBS关键点总结
    关于django中input标签中file类型以及开路由
    Bzoj1115 石子游戏Kam
    HDU1907 John
    HDU2509 Be the Winner
    洛谷P1082 同余方程
    POJ1065 Area
    Vijos1889 天真的因数分解
    Bzoj2440 完全平方数
    Bzoj2705 Longge的问题
  • 原文地址:https://www.cnblogs.com/kinglandsoft/p/14539211.html
Copyright © 2020-2023  润新知