打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
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;

  天色已晚,准备睡觉去了.

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
数据模块池
据说处对象,这样才能久,久到 一辈子
CreateInstance(
Objective-C 语法
C# 利用反射动态创建对象
C# 运行时动态对象创建和动态方法调用_.NET教程网——简单专业的.NET技术网站
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服