在c#中实现优先级队列最快的集合是什么?

在c#中实现优先级队列最快的集合是什么?,c#,C#,我需要为游戏服务器上的消息实现一个FIFO队列,以便它需要尽可能快地运行。每个用户都将有一个队列 队列的大小将为maxiumem(假设为2000)。该大小在运行时不会更改 只有当队列达到最大大小时,我才需要在添加新消息之前通过向后工作并删除优先级较低的消息(如果存在)来对消息进行优先级排序 优先级是可能值为1、3、5、7、10的整数 可以有多条具有相同优先级的消息 消息在分配后不能更改其优先级 应用程序是异步的,因此需要锁定对队列的访问 我目前正在使用LinkedList作为底层存储来实现它,但

我需要为游戏服务器上的消息实现一个FIFO队列,以便它需要尽可能快地运行。每个用户都将有一个队列

队列的大小将为maxiumem(假设为2000)。该大小在运行时不会更改

只有当队列达到最大大小时,我才需要在添加新消息之前通过向后工作并删除优先级较低的消息(如果存在)来对消息进行优先级排序

优先级是可能值为1、3、5、7、10的整数

可以有多条具有相同优先级的消息

消息在分配后不能更改其优先级

应用程序是异步的,因此需要锁定对队列的访问

我目前正在使用LinkedList作为底层存储来实现它,但担心搜索和删除节点会使它锁定太久

以下是我目前掌握的基本代码:

public class ActionQueue
{
    private LinkedList<ClientAction> _actions = new LinkedList<ClientAction>();
    private int _maxSize;

    /// <summary>
    /// Initializes a new instance of the ActionQueue class.
    /// </summary>
    public ActionQueue(int maxSize)
    {
        _maxSize = maxSize;
    }

    public int Count
    {
        get { return _actions.Count; }            
    }

    public void Enqueue(ClientAction action)
    {
        lock (_actions)
        {
            if (Count < _maxSize)
                _actions.AddLast(action);
            else
            {
                LinkedListNode<ClientAction> node = _actions.Last;
                while (node != null)
                {
                    if (node.Value.Priority < action.Priority)
                    {
                        _actions.Remove(node);
                        _actions.AddLast(action);
                        break;
                    }

                    node = node.Previous;

                }                    
            }
        }
    }

    public ClientAction Dequeue()
    {
        ClientAction action = null;

        lock (_actions)
        {
            action = _actions.First.Value;
            _actions.RemoveFirst();
        }

        return action;
    }

}
公共类操作队列
{
私有LinkedList_actions=新建LinkedList();
私有int_maxSize;
/// 
///初始化ActionQueue类的新实例。
/// 
公共操作队列(int-maxSize)
{
_maxSize=maxSize;
}
公共整数计数
{
获取{return\u actions.Count;}
}
公共作废排队(客户端操作)
{
锁定(_操作)
{
如果(计数<_最大值)
_actions.AddLast(action);
其他的
{
LinkedListNode节点=_actions.Last;
while(节点!=null)
{
if(node.Value.Priority
我假设您可以有重复的优先级


<>在.NET中没有容器,允许重复的键类似于C++ MultMAP。您可以通过几种不同的方式来实现这一点,或者使用一个SortedList,其中每个优先级键都有一个值数组(并从该数组中提取第一项作为返回值);SortedList是一个位于下面的平衡树(IIRC),应该会给您提供良好的插入和检索性能。

C5.IntervalHeap
类中可以找到一个经过审查的C#/.NET优先级队列实现。

如果您有固定的优先级,我只需要创建一个复合队列类来包装两个或多个私有队列

下面是一个大大简化的示例,不过您可以通过添加优先级枚举和开关来扩展它,以确定在何处将项目排队

class PriorityQueue {

    private readonly Queue normalQueue = new Queue();
    private readonly Queue urgentQueue = new Queue();

    public object Dequeue() {
        if (urgentQueue.Count > 0) { return urgentQueue.Dequeue(); }
        if (normalQueue.Count > 0) { return normalQueue.Dequeue(); }
        return null;
    }

    public void Enqueue(object item, bool urgent) {
        if (urgent) { urgentQueue.Enqueue(item); }
        else { normalQueue.Enqueue(item); }
    }
}

这实际上取决于您可能看到的队列长度的分布。2000年是最大值,但平均值是多少,分布情况如何?如果N通常很小,那么一个简单的列表,用蛮力搜索下一个最低点可能是一个不错的选择

您是否对应用程序进行了分析,以了解这是一个瓶颈


因此,我们具有以下特性:

public class BoundedPriorityQueue<T>
{
    private object locker;
    private int maxSize;
    private int count;
    private LinkedList<T>[] Buckets;

    public BoundedPriorityQueue(int buckets, int maxSize)
    {
        this.locker = new object();
        this.maxSize = maxSize;
        this.count = 0;
        this.Buckets = new LinkedList<T>[buckets];
        for (int i = 0; i < Buckets.Length; i++)
        {
            this.Buckets[i] = new LinkedList<T>();
        }
    }

    public bool TryUnsafeEnqueue(T item, int priority)
    {
        if (priority < 0 || priority >= Buckets.Length)
            throw new IndexOutOfRangeException("priority");

        Buckets[priority].AddLast(item);
        count++;

        if (count > maxSize)
        {
            UnsafeDiscardLowestItem();
            Debug.Assert(count <= maxSize, "Collection Count should be less than or equal to MaxSize");
        }

        return true; // always succeeds
    }

    public bool TryUnsafeDequeue(out T res)
    {
        LinkedList<T> bucket = Buckets.FirstOrDefault(x => x.Count > 0);
        if (bucket != null)
        {
            res = bucket.First.Value;
            bucket.RemoveFirst();
            count--;
            return true; // found item, succeeds
        }
        res = default(T);
        return false; // didn't find an item, fail
    }

    private void UnsafeDiscardLowestItem()
    {
        LinkedList<T> bucket = Buckets.Reverse().FirstOrDefault(x => x.Count > 0);
        if (bucket != null)
        {
            bucket.RemoveLast();
            count--;
        }
    }

    public bool TryEnqueue(T item, int priority)
    {
        lock (locker)
        {
            return TryUnsafeEnqueue(item, priority);
        }
    }

    public bool TryDequeue(out T res)
    {
        lock (locker)
        {
            return TryUnsafeDequeue(out res);
        }
    }

    public int Count
    {
        get { lock (locker) { return count; } }
    }

    public int MaxSize
    {
        get { return maxSize; }
    }

    public object SyncRoot
    {
        get { return locker; }
    }
}
  • 优先级定义明确且有界限
  • 需要线程安全
  • 队列大小固定为2000条消息,超过此值的队列将丢弃最低的项
编写支持所有这些属性的优先级队列非常容易:

public class BoundedPriorityQueue<T>
{
    private object locker;
    private int maxSize;
    private int count;
    private LinkedList<T>[] Buckets;

    public BoundedPriorityQueue(int buckets, int maxSize)
    {
        this.locker = new object();
        this.maxSize = maxSize;
        this.count = 0;
        this.Buckets = new LinkedList<T>[buckets];
        for (int i = 0; i < Buckets.Length; i++)
        {
            this.Buckets[i] = new LinkedList<T>();
        }
    }

    public bool TryUnsafeEnqueue(T item, int priority)
    {
        if (priority < 0 || priority >= Buckets.Length)
            throw new IndexOutOfRangeException("priority");

        Buckets[priority].AddLast(item);
        count++;

        if (count > maxSize)
        {
            UnsafeDiscardLowestItem();
            Debug.Assert(count <= maxSize, "Collection Count should be less than or equal to MaxSize");
        }

        return true; // always succeeds
    }

    public bool TryUnsafeDequeue(out T res)
    {
        LinkedList<T> bucket = Buckets.FirstOrDefault(x => x.Count > 0);
        if (bucket != null)
        {
            res = bucket.First.Value;
            bucket.RemoveFirst();
            count--;
            return true; // found item, succeeds
        }
        res = default(T);
        return false; // didn't find an item, fail
    }

    private void UnsafeDiscardLowestItem()
    {
        LinkedList<T> bucket = Buckets.Reverse().FirstOrDefault(x => x.Count > 0);
        if (bucket != null)
        {
            bucket.RemoveLast();
            count--;
        }
    }

    public bool TryEnqueue(T item, int priority)
    {
        lock (locker)
        {
            return TryUnsafeEnqueue(item, priority);
        }
    }

    public bool TryDequeue(out T res)
    {
        lock (locker)
        {
            return TryUnsafeDequeue(out res);
        }
    }

    public int Count
    {
        get { lock (locker) { return count; } }
    }

    public int MaxSize
    {
        get { return maxSize; }
    }

    public object SyncRoot
    {
        get { return locker; }
    }
}
公共类BoundedPriorityQueue
{
私人物品储物柜;
私有int-maxSize;
私人整数计数;
私有LinkedList[]存储桶;
public BoundedPriorityQueue(int bucket,int maxSize)
{
this.locker=新对象();
this.maxSize=maxSize;
此值为0.count;
this.bucket=newlinkedlist[bucket];
for(int i=0;i=bucket.Length)
抛出新的IndexOutOfRangeException(“优先级”);
存储桶[优先级].AddLast(项目);
计数++;
如果(计数>最大大小)
{
unsafedeadwardlowstitem();
断言(计数x.计数>0);
if(bucket!=null)
{
res=bucket.First.Value;
bucket.RemoveFirst();
计数--;
返回true;//找到项,成功
}
res=默认值(T);
return false;//未找到项,失败
}
私有void UnsafeDiscardLowestItem()
{
LinkedList bucket=bucket.Reverse().FirstOrDefault(x=>x.Count>0);
if(bucket!=null)
{
bucket.RemoveLast();
计数--;
}
}
公共图书馆(T项目,国际优先)
{
锁(储物柜)
{
返回TryUnsafeEnqueue(项目,优先级);
}
}
公共bool TryDequeue(out T res)
{
锁(储物柜)
{
返回tryunsafeedequeue(out res);
}
}
公共整数计数
{
获取{lock(locker){return count;}}
}
公共整数最大值
{
获取{return maxSize;}
}
公共对象同步根
{
获取{return locker;}
}
}
支持O(1)时间内的入/出队列,TryEnqueue和TryDequeue方法保证是线程安全的,集合的大小永远不会超过您在构造函数中指定的最大大小

TryEnqueue和TryDequeue上的锁是非常细粒度的,因此每当需要批量加载或卸载数据时,您可能会受到性能的影响