使用对象池提高性能
对象池在某些情况下可能非常有效,从而显著提高性能。 重用对象以获得最佳优势的总体思路是,尽可能多地汇集资源,将初始化从实际执行的工作中分离出来,然后在部署时根据实际硬件以管理方式调整资源池特征。 也就是说,应按照以下步骤进行操作:
- 编写对象,以排除为任何客户端执行的昂贵初始化和资源获取,这是代表客户端进行实际工作的先决条件。 编写繁重的对象构造函数来汇集尽可能多的资源,以便这些资源由对象持有,并在客户端从池中获取对象时立即可用。
- 以管理方式配置池以实现可用硬件资源的最佳平衡,通常使用专用于维护一定大小的池的内存来换取更快的客户端访问和使用对象。 在某些时候,池化将实现递减的回报,可以获得足够好的性能,同时限制特定组件可能使用的资源。
执行实际工作或获取资源
如果你有一个客户端会短暂地连续使用的组件,并且在为客户端执行特定工作之前,对象使用时间的很大一部分花在获取资源或初始化上,那么编写组件以使用对象池将是一大胜利。
可以编写组件,以便在对象的构造函数中执行尽可能多的耗时工作,以便为所有客户端执行统一的工作:获取一个或多个连接、运行脚本、从文件或通过网络提取初始化数据等。 这具有池化所有此类资源的效果。 你需要池化执行某些工作所需的资源和通用状态的组合。
在这种情况下,当客户端从池中获取对象时,它们会立即获得这些资源。 通常,他们会使用该对象来完成一些小的工作单元,推送或拉取数据,然后该对象会调用 IObjectContext::SetComplete 或 IObjectContext::SetAbort 并返回。 有使用这样的快速火力使用模式,池化可以带来出色的性能优势。 可以充分利用无状态自动事务编程模型的简单性,同时实现与传统有状态组件相当的性能。
但是,如果客户端每次调用一个对象时都要长时间使用它,那么池化就没有什么意义了。 随着使用时间相对于初始化时间的增加,获得的速度优势微乎其微。 得到的回报递减,可能无法证明保存活动对象池所需的内存成本是合理的。
跨多个客户端共担成本
分解初始化的一种变体是,可以使用池化以统计方式分摊获取昂贵资源的成本。 如果你承担了一次获取或初始化的风险,然后重用该对象,那么在该对象的生命周期内,你将在使用该对象的所有客户端中分担该成本。 每个对象仅产生一次繁重的施工时间。
预分配对象
如果指定了一个非零的最小池大小,那么在应用程序启动时,将创建并池化该最小数量的对象,为调用该应用程序的任何客户端做好准备。
通过池管理管理资源使用
可以使用最大池大小来非常精确地管理资源的使用方式。 例如,如果已获得一定数量的数据库连接许可,则可以随时控制打开的连接数。
考虑客户端使用模式、对象使用特征和物理资源(如内存和连接)时,需要会在进行性能调优时找到一些最佳平衡点。 池化对象在某个时间之后将产生递减收益。 可以确定需要什么级别的性能,并将其与实现该性能所需的资源进行平衡。
为了便于在配置对象池时进行性能调整,可以监视应用程序中组件的对象统计信息。 有关详细信息,请参阅监视对象统计信息。
提高激活 JIT 的组件的性能
对象池非常适用于 COM+ 实时激活服务。 通过将激活 JIT 的对象池化,可以加快对象的重新激活速度。 可以通过 JIT 激活保持渠道畅通,同时降低重新激活的成本。 在这种情况下,可以使用池化来控制希望为具有活动引用的对象分配多少内存。
在激活 JIT 的组件是事务性组件时,最有可能对它们进行池化。 对象池为处理事务性组件而优化。 有关详细信息,请参阅池化事务性对象。
相关主题