⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 在电子商务环境中通过使用对象池获得可伸缩性.htm

📁 在电子商务环境中通过使用对象池获得可伸缩性
💻 HTM
📖 第 1 页 / 共 5 页
字号:
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>使用管理性的池管理措施管理资源的使用情况 — 例如,通过设置合适的最大池等级,能打开的数据库连接的数量应该与所拥有的许可证数量相同。 
    </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>管理性地配置池以最充分地利用可用的硬件资源(池的配置可以随着可用硬件资源的改变而改变)。 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>减少使用实时 (JIT) 激活的对象重新激活的时间,同时小心地控制资源专用于客户端的方式。 </P></TD></TR></TBODY></TABLE>
<DIV style="MARGIN-BOTTOM: 10px; MARGIN-TOP: 3px"><A 
href="http://www.microsoft.com/china/msdn/library/windev/componentdev/CDscalobjpool.mspx#top"><IMG 
alt=返回页首 border=0 height=9 src="在电子商务环境中通过使用对象池获得可伸缩性.files/arrow_px_up.gif" 
width=7></A><A class=topOfPage 
href="http://www.microsoft.com/china/msdn/library/windev/componentdev/CDscalobjpool.mspx#top">返回页首</A></DIV><A 
name=XSLTsection123121120120></A>
<H2>对象池简介</H2>
<P>池是以每个组件为基础进行配置和维护的。池由对象组成,所有对象都有给定的 CLSID 
,但是事务性对象除外。借助事务性对象,子池能够在事务挂起时包含有事务关系的对象。 </P>
<P>当应用程序启动时,只要对象创建成功,池将被填充为您管理性指定的最小级别。当客户端对组件的请求到来时,池会按照先到先服务的顺序满足这些请求。如果没有池化的对象可用,而且池还没有达到它的指定最大等级,则会为客户端创建并激活一个新对象。 
</P>
<P>当池达到它的最大等级时,客户端请求将排入队列,每个请求都将获得池中第一个可用的对象。对象的数量(包括激活的和停用的)永远不会超过池的最大值。对象创建请求在管理性指定的期间后将超时,因此您可以控制客户端等待对象创建的时间有多长。</P>
<P>通常对象池在创建时间比使用时间长的情况下最有用,如图 1 所示。 </P>
<DIV style="WIDTH: 396px"><IMG alt=scalobjpool1.gif border=0 height=229 
src="在电子商务环境中通过使用对象池获得可伸缩性.files/scalobjpool1.gif" width=396><BR>
<P class=figureCaption><B>图 1. 对象池使用场景</B></P>
<DIV class=figureRule></DIV></DIV>
<P>您可能在对象具备如下特征的时候想要使用对象池: </P>
<TABLE border=0 cellPadding=0 cellSpacing=0>
  <TBODY>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>使用数据库连接 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>从磁盘/注册表初始化 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>使用套接字连接 </P></TD></TR></TBODY></TABLE>
<P>您在对象具备如下特征的时候不想使用对象池: </P>
<TABLE border=0 cellPadding=0 cellSpacing=0>
  <TBODY>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>只创建和使用一次 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>使用花费的时间比初始化花费的时间长得多 </P></TD></TR></TBODY></TABLE>
<P>但是这些性能增强措施也带来了约束。创建可池化对象时,您要受如下条件的约束: </P>
<TABLE border=0 cellPadding=0 cellSpacing=0>
  <TBODY>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>这时候对象必须用 Microsoft Visual C++ 编写。Microsoft Visual Basic 6.0 
      不支持可池化对象的创建。 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>事务登记必须手动处理。 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>必须将对象编写为不含有任何上下文特定的状态。 </P></TD></TR></TBODY></TABLE>
<H3>对象池与连接池</H3>
<P>对象池与连接池不同。连接池使应用程序能够使用来自连接池的数据库连接,连接池无需每次使用时再重新建立。当连接在池中创建和放置之后,应用程序可以重用该连接,无需再执行完整的连接过程。这一功能在开放数据库连接 
(ODBC) 和 Microsoft 数据访问组件 (MDAC) 2.0 中的 OLEDB 里都可使用。可以将它看成是与持久资源的非持久连接。</P>
<P>而另一方面,对象池允许一个应用程序在无需花费对象初始化成本的情况下使用来自池中的对象。它还允许请求在超时的情况下优雅地失败。如果池化连接超时,会返回一个错误给调用者。但是在池化对象的情况下,对象可以再次尝试,也可以选择返回错误给调用者。</P>
<P>图 2 显示了池化连接的场景。在这里,业务对象使用 ODBC 或者 OLEDB 提供了一个数据库连接池。 </P>
<DIV style="WIDTH: 327px"><IMG alt=scalobjpool2.gif border=0 height=83 
src="在电子商务环境中通过使用对象池获得可伸缩性.files/scalobjpool2.gif" width=327><BR>
<P class=figureCaption><B>图 2. 连接池场景</B></P>
<DIV class=figureRule></DIV></DIV>
<P>图 3 说明了对象池场景。这里业务对象调用了一个拥有数据对象池的 COM+ 服务器,每个数据对象都有与数据库的连接。</P>
<DIV style="WIDTH: 442px"><IMG alt=scalobjpool3.gif border=0 height=83 
src="在电子商务环境中通过使用对象池获得可伸缩性.files/scalobjpool3.gif" width=442><BR>
<P class=figureCaption><B>图 3. 对象池场景</B></P>
<DIV class=figureRule></DIV></DIV>
<P>对象池和连接池还有如下区别: </P>
<TABLE border=0 cellPadding=0 cellSpacing=0>
  <TBODY>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P><I>速度。</I>池化数据对象速度经证明大约是使用连接池的两倍。 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P><I>成本增加。</I>对象池并不增加成本。想像一下这样的情景,一个服务器对象与两个不同的数据库连接。如果使用连接池,每个数据库将必须都有一个单独的池。如果使用对象池,则每个对象将与每个数据库都有连接,因此无需额外的池。 
      </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P><I>事务。</I>连接池中的连接总是要在事务中登记,因此使用这些连接的对象都不用在事务中显式地登记。而另一方面池化对象则必须显式地在事务中登记。 
      </P></TD></TR></TBODY></TABLE>
<H3>对象池、资源分配器与资源管理器</H3>
<P>对象池、资源分配器和资源管理器之间的区别是另一个容易产生混淆的主题。</P>
<P>资源分配器是一种管理进程内非持久资源的服务。如,ODBC 或者 OLEDB 的资源分配器就负责管理数据库连接池,它们是在 Microsoft 
Transaction Server (MTS) 2.0 
中引入的。它们非常方便,因为事务的登记和连接的池化都是自动的。资源也可以通过设置一个超时值进行垃圾回收。但是它们也有缺点。您无法配置资源池的大小 — 
分配直到数据库连接或者内存耗尽的时候才进行。资源分配器是底层的实体,不容易创建。</P>
<P>资源管理器是维护持久数据的一个子系统,如 Microsoft SQL Server脗聶。资源管理器将与事务管理器一起共同保证事务能正确地得到处理。</P>
<P>您可以把对象池想像成“轻量级的”资源分配器,因为事务登记可以自动进行,而且实际上通常都配置为执行连接池化(每个对象有一个数据库连接)。但是对于对象池,您没有义务提供资源分配器。您可以分别配置对象池的大小和数据库连接的数量,您对错误处理有更多的控制权(如客户端要求一个数据库连接,但是一个数据库连接都没有的时候)。也就是说,通常您应该只在应用程序的可伸缩性需求需要的时候,才使用对象池。</P>
<H3>可池化对象的设计需求</H3>
<P>可池化对象必须满足一些需求,才能使一个对象实例被多个客户端使用,并且与操作系统协同工作。可池化对象必须满足: </P>
<TABLE border=0 cellPadding=0 cellSpacing=0>
  <TBODY>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P><I>没有客户端特定的状态。</I>为了维护安全性、一致性和独立性,可池化对象应该不从客户端到客户端保存客户端特定的状态。您可以使用 
      <B>IObjectControl</B> 管理任何基于客户端的状态,用 <B>Activate</B> 执行上下文特定的初始化,用 
      <B>Deactivate</B> 清除任何客户端的状态。 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P><I>没有线程关系。</I> 
      可池化对象不能与特定的线程绑定,否则对性能的影响可能是灾难性的。因此,可池化对象不能标记为单元模型,而是必须运行在多线程单元或者线程中立单元中(换句话说,它们必须标记为 
      Free、Neutral 或者 Both)。此外,可池化对象不应该使用线程本地存储区 (TLS),也不应该聚合自由线程封送拆收器 (FTM)。请注意 
      Visual Basic 6.0 只能创建单元模型的组件。因此,Visual Basic 6.0 组件不能池化。Visual Basic 7.0 
      组件将能够池化。 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P><I>可聚合。</I>可池化对象必须支持聚合 — 也就是说,它们必须支持用 pUnkOuter != NULL 的方式创建。当 COM+ 
      激活池化对象时,它将创建一个聚合来管理池化对象的生存期并调用 <B>IObjectControl</B> 的方法。 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P><I>实现 IObjectControl。</I> 可池化对象应该实现 <B>IObjectControl</B>,虽然严格地说这不是必需的。 
      </P></TD></TR></TBODY></TABLE>
<P>此外还必须考虑如下问题: </P>
<TABLE border=0 cellPadding=0 cellSpacing=0>
  <TBODY>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P><I>事务性组件。</I>参与事务的可池化对象必须手动登记托管资源。如果您的对象在池化时拥有一个托管资源(如数据库连接),则在给定上下文中激活对象时,资源管理器将没有办法在事务中自动登记。所以,对象本身必须处理检测事务、关闭资源管理器的自动登记和手动登记它拥有的任何资源等逻辑。这对于编码而言可不是小事。此外,事务性池化对象应该在 
      <B>IObjectControl::CanBePooled</B> 中反映其资源的当前状态。 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P><I>语言限制。</I>当前,使用 Visual Basic 开发的组件不能池化,因为这些组件将是单元模型线程的,虽然 Visual 
      Basic 7 将解决这一问题。 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P><I>旧式组件。</I> 只要组件是非事务性的,而且遵守以前的相应需求,则即使编写它们的时候并没有专门考虑池,也可以池化组件。实现 
      <B>IObjectControl</B> 并不是必要的;不可池化的组件只不过不参与管理其生命期而已。如果 <B>CanBePooled</B> 
      没有实现,对象将总是被重用,直至池达到最大大小为止。 </P></TD></TR></TBODY></TABLE>
<H3>实现 IObjectControl</H3>
<P>池化对象可以实现 <B>IObjectControl</B> 
以控制对其重用的方式。这使它们能够在给定上下文中激活的时候执行初始化,能够在停用时清除任何客户端状态,并指示什么时候它们处于不可重用状态。</P>
<P>池化对象应该实现 <B>IObjectControl</B> 以参与 COM+ 
管理它在池中的激活和停用。当池化对象创建时,它聚合到一个更大的对象中,后者将通过在对象的生命周期的一些固定点调用 <B>IObjectControl</B> 
的方法来管理对象: </P>
<TABLE border=0 cellPadding=0 cellSpacing=0>
  <TBODY>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>当对象返回客户端并在特定的上下文中激活时,调用 <B>Activate</B> 方法。 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>当对象被客户端释放,或者对于 JIT 激活的对象,当它停用时,调用 <B>Deactivate</B> 方法。 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>当对象返回到通用池时调用 <B>CanBePooled</B> 方法。 </P></TD></TR></TBODY></TABLE>
<P>除了事务性对象以外,实现 <B>IObjectControl</B> 是可选的,事务性对象将总是实现 <B>CanBePooled</B> 
以监视它们所拥有的资源的状态,这一点将在稍后讨论。但是,在大多数情况下,实现 <B>IObjectControl</B> 
都是可取的,因为它提供了管理池化对象行为的如下高效方式: </P>
<TABLE border=0 cellPadding=0 cellSpacing=0>
  <TBODY>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>通过执行上下文特定的初始化 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>清除任何客户端状态 </P></TD></TR>
  <TR>
    <TD class=listBullet vAlign=top>&#8226;</TD>
    <TD class=listItem>
      <P>控制对象的重用 </P></TD></TR></TBODY></TABLE>
<P><B>执行上下文特定的初始化</B></P>
<P>您可以使用 <B>IObjectControl::Activate</B> 
初始化上下文(对象在此为给定客户端激活)中的对象。例如,您可能获取与上下文相关联的 
transactionID,但是需要确定对象是否有事务关系,因为其资源可能已经登记了。 </P>
<P>通常,您使用 <B>Activate </B>执行初始化,这对于对象公开的任何方法都是一致的,将它当作对象构造函数的上下文特定部分。 </P>
<P><B>清除任何客户端状态</B></P>
<P>您可以使用 <B>IObjectControl::Deactivate</B> 
删除任何现有的客户端特定状态。您应该确保对象返回到处于完全一般状态中的池,因此任何客户端可以在不损害安全或者独立性的情况下使用它。 </P>
<P><B>控制对象的重用</B></P>
<P>您可以使用 <B>IObjectControl::CanBePooled</B> 来监视您对象的内部状态,并报告它是否适合重用。如果 
<B>CanBePooled</B> 返回 TRUE,并且还没有达到池的最大量,对象将放回通用池中。如果 <B>CanBePooled</B> 返回 
FALSE,对象将被抛弃。对于事务性组件,返回 FALSE 将注定中止当前事务。 </P>
<P>您通常要保留对象的一些全局数据成员。如果您检测出一个连接已经有问题了,或者某种资源处在不良状态,您应该设置全局数据成员反映当前情况并通过 
<B>CanBePooled</B> 返回它。请注意从 <B>CanBePooled</B> 返回 FALSE 将注定中止事务。</P>
<P>如果一个对象不实现 <B>CanBePooled</B>,实例将总是被重用,直至达到池的最大等级为止。 </P>
<P>如下 C++ 代码说明了这些操作如何实现。它假设您的对象派生自 <B>IObjectControl</B>,如下面的活动模板库 (ATL) 
代码所示:</P><PRE class=codeSample>class ATL_NO_VTABLE CMyObject : 
   public CComObjectRootEx&lt;CComSingleThreadModel&gt;,
   public CComCoClass&lt;CLogFile, &amp;CLSID_MyObject&gt;,
   public IDispatchImpl&lt;ILogFile, &amp;IID_IMyObject, 
      &amp;LIBID_MYOBJECTLib&gt;,
   public IObjectControl
{
. . .
HRESULT Activate()
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -