代码之家  ›  专栏  ›  技术社区  ›  Fredrik Mörk

设计模式:管理有限数量的资源

  •  4
  • Fredrik Mörk  · 技术社区  · 16 年前

    我正在为一个系统设计一个特性,在这个系统中,我强烈地感觉必须有一个模式来实现这个特性,在深入到代码中之前我应该知道这个模式。

    场景是这样的:

    • 我有一个有限数量的资源池。
    • 我使用这些资源的消费者数量是可变的;每个消费者只需要一个资源,在给定的时间内,它可能不会使用与任何其他消费者相同的资源。
    • 用户被分成固定数量的组,系统需要保证每个组至少有一个资源。
    • 每个组中的消费者数量随时间而变化;根据需要分配和分配。

    我目前的方法是在启动时将资源放入两个堆栈:一个“紧急堆栈”和一个“公共堆栈”。应急堆栈将包含与组相同数量的资源(因此,每个组一个)。其余的可用资源进入公共堆栈。

    当要创建新的使用者时,系统将请求一个资源。如果公共堆栈中有可用的资源,将从中弹出一个资源并返回给调用方。如果公共堆栈为空,则可以从紧急堆栈中弹出一个资源, 但前提是同一组中没有已经拥有紧急资源的消费者 .

    每当组中的使用者可以被释放时,关联的资源将被返回,并推送到其中一个资源堆栈上。负责解除分配消费者的代码将确保总是先返回任何紧急资源,以便在将返回的资源推送到公共堆栈之前填充紧急堆栈。

    我觉得这是一个应该存在的问题,设计模式已经过测试并被证明是有效的,所以我呼吁社区:你知道这样的模式吗?如果是这样,我恳请你开导我。

    更新

    这个解决方案现在已经实现,使用这个问题的各种答案中的零碎部分。我发表 a blog post 关于它。

    5 回复  |  直到 16 年前
        1
  •  2
  •   Steve314    16 年前

    我可能只有一个资源栈,一个按计数组键控的数组/映射,以及一个没有资源的组的计数。

    分配…

    if group-counts [group] == 0
      pop resource from stack
      increment group-counts [group]
      decrement reserved-count
    
    elseif reserved-count < stack.size
      pop resource from stack
      increment group-counts [group]
    
    else
      fail
    

    关键是,永远不允许堆栈小于仍有权要求立即资源的组的数目。

    这种方法的一个优点是,如果需要,您可以使它更灵活一些。假设一个组有一个特殊的需求,那么它在任何时候都可能需要两个资源。

    if group-counts [group] < group-reserved [group]
      pop resource from stack
      increment group-counts [group]
      decrement reserved-count
    
    elseif reserved-count < stack.size
      pop resource from stack
      increment group-counts [group]
    
    else
      fail
    

    在这种情况下,保留的计数以所有组保留的[]值的总和开始。

    这个案例的发布逻辑是…

    push resource to stack
    decrement group-counts [group]
    if group-counts [group] < group-reserved [group]
      increment reserved-count
    

    对于简单情况,使用“if group counts[group]==0”。

        2
  •  2
  •   Daren Thomas    16 年前

    您还可以交换逻辑(这可能导致更清晰的代码):

    从一开始就为每个组分配一个资源。将其余资源保留在“免费”资源列表中。 任何请求资源的使用者都是通过一个组资源分配程序来实现的,该分配程序要么只给出默认的组资源,要么查询一个自由资源。 在返回资源时,首先填充组资源孔,然后开始填充自由资源列表。

    所以你最终得到了一个免费的资源池。 每组一个资源分配器,可以访问可用资源池和默认资源。 使用者与组分配器交互。

        3
  •  2
  •   Daniel Rikowski    16 年前

    我不知道任何模式,但我想你可以 简化 你的方法:

    如果您的资源池知道哪个组有资源,则不需要额外的紧急堆栈。

    1. 提供同一堆栈中的所有资源。
    2. 如果 可用资源 小于 保证资源 使用保证资源 ,如果请求组已有资源,则不返回资源。

    除此之外,我认为你的方法是合理和简洁的,我不认为有更好的方法。(当然,我可能错了)

        4
  •  1
  •   Pete Kirkham    16 年前

    这看起来确实是一个非常奇怪的版本的池。

    例如,如果在默认池中有七个组和七个资源,则在“紧急”池中有七个。如果每个组请求一个资源,则默认池将耗尽;如果任何一个组请求,则会再次发生两个资源不足,14个资源中只有8个在使用中。即使您将其更改为首先使用特定于组的资源,您仍然会发现只有8/14利用率的饥饿情况。

    为什么资源的第二个请求应该是失败的请求而不是第一个请求(另一种方法是查看“每个组至少有一个资源”需求)很重要?

        5
  •  0
  •   Falaina    16 年前

    这很有趣。从高层来看,问题在于有两种类型的资源请求:不允许失败的高优先级请求和可能失败的标准请求。

    处理这一问题的一种可能方法是,是否可以暂停您的消费者。如果可能,您可以在消费者和经理之间实现双向通信。

    消费者可以请求资源或释放资源

    经理可以撤消资源

    当管理器收到一个正常的请求时,如果没有空闲资源,它将拒绝它。如果它收到一个优先级请求,它将强制对某些消费者进行撤销(由某个优先级策略决定)。这类似于分布式锁系统的工作方式。这可以防止饥饿,但会极大地增加复杂性,甚至在消费者刚开始就必须运行到完成时也不可能实现。

    如果不能做到这一点,我认为达伦的回答可能是最理想的,但是,如果你在一个群体中没有活跃的消费者,而在另一个群体中有许多活跃的消费者,你仍然有浪费的风险。不过,这可以通过对组进行良好的划分来减轻。

    推荐文章