【问题标题】:How can I correctly determine the active instances in a circular pool?如何正确确定循环池中的活动实例?
【发布时间】:2021-03-19 08:55:23
【问题描述】:

我有一个循环池实现

public class CircularPool<T> where T : class, new()
{
    private readonly Queue<T> instances;
    
    public CircularPool(int size)
    {
        instances = new Queue<T>(size);
        
        for (var i = 0; i < size; ++i)
        {
            instances.Enqueue(new T());
        }
    }

    public T GetInstance()
    {
        var instance = instances.Dequeue();
        instances.Enqueue(instance); // Circular pool
        return instance;
    }

    public void ReturnInstance(T instance)
    {
        // What does returning look like?
        // Could use IsActive flag?
    }

    public IEnumerable<T> GetActiveInstances()
    {
        return instances;  // TODO: Only want the active ones
    }
}

我希望能够跟踪池中当前正在使用的实例,以便对它们进行迭代并执行各种操作

var pool = new CircularPool<Foo>(5);
var fooInstanceA = pool.GetInstance();
var fooInstanceB = pool.GetInstance();
var fooInstanceC = pool.GetInstance();

pool.ReturnInstance(fooInstanceB);

foreach (var activeInstance in pool.GetActiveInstances())
{
    // Do stuff with active instances (fooInstanceA then fooInstanceC)
}

如何正确获取按年龄排序的活跃实例?

假设这是一个循环池,那么如果调用 GetInstance 的次数超过了池的大小而没有调用 ReturnInstance,则返回最旧的活动实例并成为最年轻的活动实例。这应该相应地反映在 GetActiveInstances 中。

另外,在循环池的上下文中 ReturnInstance 应该是什么样子?

【问题讨论】:

  • '循环池'据我所知不是常见的数据结构之一。您打算将数据结构用于什么?它必须履行的合同是什么?还是您的意思是环形缓冲区或对象池?
  • 我认为您需要另一个Queue 来保存活动项目。

标签: c# queue


【解决方案1】:

好吧,我们可以将数组T[] 用于所有实例,将HashSet&lt;T&gt; 用于活动

public class CircularPool<T> where T : class, new() {
  private readonly T[] m_All;
  private readonly HashSet<T> m_InUse;

  private int m_Index; // Index to start looking for a free instance

  public CircularPool(int size) {
    if (size <= 0)
      throw new ArgumentOutOfRangeException(nameof(size));

    m_InUse = new HashSet<T>(size);
    m_All = Enumerable.Range(0, size).Select(_ => new T()).ToArray();
  }

  public bool TryGetInstance(out T availableInstance) {
    for (int i = 0; i < m_All.Length; ++i) {
      int index = (i + m_Index) % m_All.Length;

      if (m_InUse.Add(m_All[index])) {
        availableInstance = m_All[index];
        m_Index = index + 1;

        return true;
      }
    }

    availableInstance = default(T); // no available instances found
    return false;
  }

  public T GetInstance() => TryGetInstance(out var result)
    ? result
    : throw new InvalidOperationException("There are no available instances.");

  public bool ReturnInstance(T instance) => m_InUse.Remove(instance);

  public IEnumerable<T> GetActiveInstances() => m_InUse;

  public IEnumerable<T> GetAvailableInstances() => 
    m_All.Where(item => !m_All.Contains(item));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-15
    • 2021-12-02
    • 2016-11-22
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 2016-08-23
    • 2017-10-05
    相关资源
    最近更新 更多