《面向模式的软件体系结构3资源管理模式》读书笔记(6) Pooling模式

3.2 Pooling模式

      Pooling(池)模式描述了如何通过循环使用不再需要的资源来避免昂贵的获取和释放资源的操作。一旦资源被循环利用并置入池中,它们就失去了自己的标识和状态。

1.问题

      很多系统都要求对资源可以进行快速并且可预测的访问。这样的资源包括网络连接,对象实例,线程以及内存。除了提供快速以及可预测的资源访问外,系统还要求解决方案对于所用资源的数目具有可伸缩性。此外,每一次用户请求应当在访问时间内经历很少的变化。所以,对资源A的获取时间不应当同资源B的获取时间有显著不同(A和B是相同类型的资源)。为了解决上面提到的问题,需要解决以下几点:

      1)可伸缩性(Scalability)。被释放的资源应当被重用,以避免重复获得的开销。

      2)性能(Performance)。应当避免反复获取和释放资源造成的CPU周期的浪费。

      3)可预测性(Predictability)。资源使用者获取资源的时间应该是可预测的(即便从资源提供者直接获取资源的时间可能是不可预测的)。

      4)简单性(Simplicity)。解决方案应该比较简单,以便尽量减少应用程序的复杂性。

      5)稳定性(Stability)。反复获取和释放资源可能会增加系统不稳定性的风险。例如,反复获取和释放内存可能会对没有复杂的内存管理机制的操作系统导致内存碎片化。解决方案应该尽量减少系统的不稳定性。

2.解决方案

      在池中管理一类资源的多个实例。这个资源池使得我们可以重用被资源使用者释放的不再需要的资源。被释放的资源会被放回到池中。

      为了增加效率,资源池会在创建后预先获取固定数目的资源。如果对资源的需求超过了池中的资源数目,它会延迟地获取更多的资源。要释放不用的资源,可以有多种选择,比如Evictor模式或者Leasing模式所记录的方法。

      当资源被释放并放回到池中时,资源使用者或者资源池应当让它失去其标识,这取决于所用的策略。之后,在被重用前,资源需要重新初始化。如果资源是一个对象,那么提供一个单独的初始化接口可能会很有用。资源使用者或者资源池不会用资源标识(在很多情况下是一个指针或者一个引用)来区分对象。

3.结构

      资源使用者获取并使用资源。

      资源是一个实体(比如内存或者线程)。

      资源池(Resource Pool)管理资源,并响应资源获取请求,将资源交给资源使用者。

      资源提供者(比如操作系统)拥有并管理资源。

      

       

4.实现

1)选择资源。找出会通过资源池获得好处的资源。通过根据类型把资源归入几个不同的资源池来简化资源管理。把不同类型的资源放入同一个池中会使得它们的管理复杂化,因为这会导致有必要划分多个子池以及进行专门的查找。

2)决定资源池的最大尺寸。为了避免资源耗尽,需要定义资源池维护的资源的最大数目。资源池中资源的最大数目等于预先获取的资源数目加上按需获得的资源数目,资源的最大数目通常是在资源池的初始化时刻设置的,但是也可以根据可配置的参数(比如系统的当前负荷)来设置。

3)决定预先获取的资源数目。为了尽量减少运行的获取资源的时间,建议预先获取至少通常情况下会用到的资源的平均数目,这会减少应用程序常规执行时的资源获取。用户需求以及系统分析有助于判断要获取的资源的平均数目。重要的是,要记住太多的预先获取的资源反而会成为负担,因为它们会导致额外的资源竞争,所以应当避免。

4)定义资源接口。提供所有放在资源池中的资源都需要实现的接口。这个接口有助于维护一组资源。

5)定义资源池接口。提供一个接口,让资源使用者可以获取和释放资源。

6)提供资源清除。池中有很多资源意味着存在大量未被使用的资源,浪费了空间,降低了性能。为了尽量减少系统性能的下降,资源池的尺寸应当减少到一个合理的大小,这可以通过从池中释放一些资源来做到。

7)决定资源循环利用语义。资源循环利用因资源类型不同而不同。例如,循环利用线程资源需要清楚它的堆栈以及初始化内存。

8)决定失败处理策略。对于任何可以恢复的资源获取或者资源释放的失败,都应当处理异常以及/或者错误消息。如果不可能从失败中恢复,那么就应当抛出异常,或者向资源使用返回空的资源。

5.结论

优点:

1)性能(Performance)。Pooling模式可以改善应用程序的性能,因为它有助于减少花在费时的释放和重新获取资源的操作上的时间。在资源已经被资源池获取的情况下,资源使用者获取资源会变得很快。

2)可预测性(Predictability)。如果资源已经被预先获取,那么资源使用者执行平均数目的资源获取是在确定时间内完成的。使用合适的清除策略,大多数获取请求都可以通过资源池来满足。因为查找和释放以前获取过的资源是可预测的,所以资源使用者获取资源与总是以资源提供者获取资源相比,也较有可预测性。

3)简单性(Simplicity)。资源使用者不需要调用额外的内存管理例程。资源使用者或者透明地,或者直接从资源池获取和释放资源。 

4)稳定性和可伸缩性(Stability and Scalability)。如果需求超过了可用的资源,那么新的资源会被创建。因为要循环利用,资源池基于清除策略延迟了资源清除,这节省了代价高昂的对资源的释放和重新获取的操作,从而增加了系统的稳定性和可伸缩性。

5)共享(Sharing)。把池作为Mediator,这样未被使用的资源就可以在资源使用者之间共享,这对内存使用也有好处,并会降低应用程序的总体内存空间开销。资源池没有同步对资源的访问。所以,如果需要同步,资源使用者必须自己做到。

缺点:

1)额外开销(Overhead)。对池中资源的管理会消耗额外的CPU周期。但是,这些CPU周期通常会小于释放和重新获取资源所需的CPU周期。

2)复杂性(Complexity)。资源使用者不得不显式地把资源释放回资源池。Leasing之类的模式可以用来解决这个问题。

3)同步(Synchronization)。在同步环境中,对资源池的获取请求必须被同步,以避免出现竞争可能破坏关联的状态。 

原文地址:https://www.cnblogs.com/pennant/p/2723738.html