RO代码跟踪 之 对象池工厂的工作原理

  要在服务端使用对象池的功能,需要在XXX_Impl中uses uROClassFactories单元,并将其initialization小节中代码
TROClassFactory.Create('FirstSampleService', Create_FirstSampleService, TFirstSampleService_Invoker);
替换为
TROPooledClassFactory.Create('FirstSampleService' ,         //前三个参数不变
                               Create_FirstSampleService,
                               TFirstSampleService_Invoker,
                               10,    //池大小
                               TROPoolBehavior.pbCreateAdditional,  当池内对象已经全部占用该如何做
                               True);  //预先生成池中的对象
  跟踪代码看看.原来TROPooledClassFactory继承于TROClassFactory.
constructor TROPooledClassFactory.Create(const anInterfaceName: string;
  aCreatorFunc: TRORemotableCreatorFunc; anInvokerClass: TROInvokerClass;
  aPoolSize : Integer; aPoolBehavior:TROPoolBehavior=pbCreateAdditional; aPreInitializePool:Boolean=false);
var i : integer;
begin
  inherited Create(anInterfaceName, aCreatorFunc, anInvokerClass);

  fCriticalSection := TCriticalSection.Create();  //线程同步

  SetLength(fInstances, aPoolSize);               //设置Array的尺寸为池大小 对象创建出来后保存在这个数组中
  fPoolSize := aPoolSize;
  fPoolBehavior := aPoolBehavior;                 //指定如果池中对象都在使用,如何处理新来的请求

  if fPoolSize < 1 then RaiseError(err_PoolSizeMustBe1orHigher,[]);
   
  //fLastInc := -1;
  if aPreInitializePool then  //如果预先生产对象,则调用基类的方法一次创建全部的对象
    for i := 0 to (fPoolSize-1) do
      inherited CreateInstance(EmptyGUID, fInstances[i].fInterface);
end;

  在看看fInstances定义:在类的private中fInstances : array of TROPoolInterfaceEntry;
  TROPoolInterfaceEntry = record
    fInterface:IInterface;
    fInUse:Boolean;
  end;

  准备就绪了,思路就是提前把一定数量的对象创建出来保存在数组中,如果你来请求的话我就给你返回一个没有使用的对象,并设置fInUse标志位.用完了我在把标志位反置.这样就不用每次都去Create对象了.
  由以前的跟踪结果可知,在服务端获取服务对象调用类工厂的CreateInstance方法:aFactory.CreateInstance(aMessage.ClientID, instance);那么这个对象池工厂类就应该要重写CreateInstance方法了.果然其中override了CreateInstance,ReleaseInstance两个方法.
procedure TROPooledClassFactory.CreateInstance(const aClientID : TGUID; out anInstance : IInterface);
var i:Integer;
    //, refcnt : integer;
begin
  anInstance := nil;
  repeat 
    fCriticalSection.Acquire();                  //加锁
    try
      for I := 0 to fPoolSize-1 do begin         //先从数组中查找没有使用的对象
        if not fInstances[i].fInUse then begin   //如果有没有使用的对象
          if not Assigned(fInstances[i].fInterface) then
            inherited CreateInstance(EmptyGUID, fInstances[i].fInterface);
          anInstance := fInstances[i].fInterface; //返回这个实例
          fInstances[i].fInUse := True;
          break;

        end;
      end; { for }

    finally
      fCriticalSection.Release();   //释放锁
    end;
    if not Assigned(anInstance) then             //如果没有找到空闲的实例
      case fPoolBehavior of                      //根据指定的行为方式
        pbFail:raise EROPoolNoFreeObjects.CreateFmt(err_NoFreeObjectsInPool,[GetInterfaceName, fPoolSize]);  //抛出异常给客户端
        pbWait:Sleep(POOL_SLEEP_MS_WHILE_WAITING);  //等待.5秒 继续循环判断  反正这是在单独线程中运行的 不用担心效率问题
        pbCreateAdditional:inherited CreateInstance(EmptyGUID, anInstance);  //创建新对象
      end;
  until (fPoolBehavior <> pbWait) or (Assigned(anInstance));  //如果找到或生成了实例 返回
end;
  实现真的好简单,系统效率提升设计思路起到决定作用.


procedure TROPooledClassFactory.ReleaseInstance(const aClientID: TGUID; var anInstance: IInterface);
var i:Integer;
begin
  fCriticalSection.Acquire();  //加锁
  try
    //如果对象是从池中获取的,则还回去(设置一下标志位),否则Free掉
    for i := 0 to fPoolSize-1 do begin
      if fInstances[i].fInterface = anInstance then begin
        anInstance := nil;
        fInstances[i].fInUse := false;
        break;
      end;
    end;
  finally
    fCriticalSection.Release();
  end;
  if Assigned(anInstance) then anInstance := nil;
end;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值