zoukankan      html  css  js  c++  java
  • 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.

  • 相关阅读:
    iOS Xcode8的适配
    iOS从生成证书到打包上架-02(详细2016-10最新)
    iOS从生成证书到打包上架-01(详细2016-10最新)
    PHP读取CSV文件
    magento批量导入评论加星
    magento调用static block
    Magento Block的几种调用方式
    JFinal项目中获取根目录
    清除UTF-8编码文件前端的DOM
    PhpStorm注册码(2,3,4,5)通用
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/2347149.html
Copyright © 2011-2022 走看看