• datasnap对象池


    {

    之前说到中间层通过向客户端暴露方法的方式提供服务,实现数据库数据的读取和更新。方法调用的方式,其潜在的意义,就是说中间层不保存客户端状态信息,就像WEB服务一样,客户端需要自己保存自己的状态信息。进一步说,就是中间层具体提供方法的业务对象实例,不是也不应该专属于某个客户端,它应该能够为不同的客户端调用提供服务。如果我们把业务对象实例放到对象池中集中存放,调用方法时随用随取,方法结束即放回池中。这样就可以实现业务对象实例服务于不同的客户端调用请求。更重要的是,利用对象池,能够最大化服务器各种资源的使用效率,而且对客户端的响应也更快了,因为业务对象实例早就创建好了,取来即用。

    其实,DataSnap构架,已经为我们的这种构想提供了现实支持。简单的说,就是改造工厂类(TDSServerClass),把LifeCycle属性改为Invocation方式;在OnCreateInstance事件中从对象池中取业务类对象实例;在OnDestroyInstance事件中把业务类对象实例放回对象池。

    ...
    procedure TsmMainForm.dssMethodsCreateInstance(
      DSCreateInstanceEventObject: TDSCreateInstanceEventObject);
    begin
      DSCreateInstanceEventObject.ServerClassInstance := ServerMethodsPool.LockPoolObject;
    end;

    procedure TsmMainForm.dssMethodsDestroyInstance(
      DSDestroyInstanceEventObject: TDSDestroyInstanceEventObject);
    begin
      ServerMethodsPool.UnlockPoolObject(TPersistent(DSDestroyInstanceEventObject.ServerClassInstance));
    end;
    ...
    当然,还有对象池类的创建和释放,也很简单,例如:
    procedure TsmMainForm.FormCreate(Sender: TObject);
    begin
      ServerMethodsPool := ObjPoolMgr.TPoolManager.Create;
      ServerMethodsPool.InstanceClass := uServerMethods.TPooledDM;
    end;

    procedure TsmMainForm.FormDestroy(Sender: TObject);
    begin
      ServerMethodsPool.Free;
    end;

    下面就是如何实现对象池技术的问题。实现对象池并不复杂,另有两个问题需要注意:

    1、多线程。中间层TDSTCPServerTransport对象提供的是多线程服务,允许同时有多个客户端请求。所以对象池类的实现,要考虑多线程情况下公共对象或变量的访问冲突问题。

    2、内存泄漏。业务类的基类,采用TDataModule、TComponent或者TPersistent都可以,但不要采用TDSServerModule,因为若采用此基类,TDSServerClass在Invocation方式下会产生内存泄漏。

    }

    unit ObjPoolMgr;

    interface

    uses
      Classes, SyncObjs, SysUtils, DSServer, DateUtils;

    type

      PServerObject = ^TServerObject;
      TServerObject = record
        ServerObject: TPersistent;
        InUse:        Boolean;
      end;

      TPoolManager = class
      private
        FCriticalSection: TCriticalSection;
        FServerObjects:   TList;
      private
        FMaxCount: Integer;
        FInstanceClass: TPersistentClass;
        function  CreateNewInstance: TPersistent; inline;
        procedure SetInstanceClass(const Value: TPersistentClass);
      public
        constructor Create(ACapicity:Integer=30); override;
        destructor Destroy; override;
        function  Lock: TPersistent;
        procedure Unlock(var Value: TPersistent);
      public
        property InstanceClass: TPersistentClass read FInstanceClass write SetInstanceClass;
        property MaxCount:Integer read FMaxCount;
      end;

    var
      ObjPool: TPoolManager;

    implementation

    constructor TPoolManager.Create(ACapicity:Integer=30);
    begin
      FMaxCount :=ACapicity;
      FServerObjects := TList.Create;
      FCriticalSection := TCriticalSection.Create;
    end;

    destructor TPoolManager.Destroy;
    var
      I: Integer;
    begin
      for I := 0 to FServerObjects.Count - 1 do
      begin
        PServerObject(FServerObjects[i]).ServerObject.Free;
        FreeMem(PServerObject(FServerObjects[i]));
      end;
      FServerObjects.Free;
      FCriticalSection.Free;
      inherited Destroy;
    end;

    procedure TPoolManager.SetInstanceClass(const Value: TPersistentClass);
    begin
      FInstanceClass := Value;
    end;

    function TPoolManager.CreateNewInstance: TPersistent;
    var
      p: PServerObject;
      Component: TComponent;
    begin
      if not Assigned(FInstanceClass) then Raise Exception.Create('Not specify class of instance!');

      FCriticalSection.Enter;
      try
        if FInstanceClass.InheritsFrom(TComponent) then
        begin
          Component := FInstanceClass.NewInstance as TComponent;
          Component.Create(nil);
          Result := Component;
        end
        else
          Result := FInstanceClass.Create;

        New(p);
        p.ServerObject := Result;
        p.InUse        := True;
        FServerObjects.Add(p);
      finally
        FCriticalSection.Leave;
      end;
    end;

    function TPoolManager.Lock: TPersistent;
    var
      i: Integer;
    begin
      FCriticalSection.Enter;
      try
        for i := 0 to FServerObjects.Count - 1 do
        begin
          if not PServerObject(FServerObjects[I]).InUse then
          begin
            PServerObject(FServerObjects[I]).InUse := True;
            Result := PServerObject(FServerObjects[i]).ServerObject;
            Exit;
          end;
        end;
      finally
        FCriticalSection.Leave;
      end;
      if FServerObjects.Count < MaxCount then
        Result := CreateNewInstance
      else
        Result := nil;
    end;

    procedure TPoolManager.Unlock(var Value: TPersistent);
    var
      i: Integer;
    begin
      FCriticalSection.Enter;
      try
        for i := 0 to FServerObjects.Count - 1 do
        begin
          if Value = PServerObject(FServerObjects[i]).ServerObject then
          begin
            PServerObject(FServerObjects[i]).InUse := False;
            Value := nil;
            Break;
          end;
        end;
      finally
        FCriticalSection.Leave;
      end;
    end;

    initialization
      ObjPool := TPoolManager.Create();
    finalization
      FreeAndNil(objpool);

    end.

  • 相关阅读:
    PHP基本的语法以及和Java的差别
    Linux 性能測试工具
    【Oracle 集群】Linux下Oracle RAC集群搭建之Oracle DataBase安装(八)
    【Oracle 集群】Oracle 11G RAC教程之集群安装(七)
    【Oracle 集群】11G RAC 知识图文详细教程之RAC在LINUX上使用NFS安装前准备(六)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 特殊问题和实战经验(五)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之缓存融合技术和主要后台进程(四)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)
    Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之ORACLE集群概念和原理(二)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之集群概念介绍(一)
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/2347149.html
Copyright © 2020-2023  润新知