.NET6 中的 PriorityQueue

Intro

.NET 6 中引入了一个新的集合类型 PriorityQueue,正如它的名字那样,在普通的 Queue 基础之上增加了优先级的支持,接下来就一起来看一下怎么使用,以及一些常用的使用场景介绍。

Get Started

来看一个简单的使用示例:

var priorityQueue = new PriorityQueue<string, int>();
priorityQueue.Enqueue("Alice", 100);
priorityQueue.EnqueueRange(Enumerable.Range(1, 5).Select(x => ($"X_{x}", 100 - x))
);while (priorityQueue.TryDequeue(out var element, out var priority))
{Console.WriteLine($"Element:{element}, {priority}");
}

输出示例:

可以看到输出的顺序和我们添加的顺序是相反的, PriorityQueueDequeue 的时候是从优先级最小开始的,值越小优先级越高,优先级越高越优先输出,如果我们希望最大先输出是不是可以呢,答案是肯定的,只是我们需要指定我们自己的优先级比较规则就可以了,可以参考后面的示例

Scenes

借助带优先级的自动排序,我们可以做一些自动排序的需求的时候可以考虑使用 PriorityQueue

Message Queue

借助 PriorityQueue 可以来实现一个优先级消息队列,允许用户在发消息的时候指定一个消息的优先级,在消费的时候就会按优先级

var random = new Random();var queue = new PriorityQueue<string, int>();
for (var i = 1; i <= 10; i++)
{queue.Enqueue($"Message_{i}", random.Next(10, 100));
}while (queue.TryDequeue(out var message, out _))
{Console.WriteLine(message);
}

在上面的示例里我们默认指定了一个 int 作为 Priority 的类型,并入队了一些消息,但是往往会有很多的消息,可能会出现优先级相同的情况,我们可以使用时间和int 作为一个联合的 Priority 类型,可以参考下面的示例:

var random = new Random();var queue = new PriorityQueue<string, (DateTime time, int priority)>(new DateTimePriorityComparer());var time = DateTime.UtcNow;
Thread.Sleep(1000);
for (var k = 0; k < 3; k++)
{for (var i = 1; i <= 3; i++){queue.Enqueue($"Message_{i}_{k}", (i > 2 ? time : DateTime.UtcNow, random.Next(5, 10)));}
}while (queue.TryDequeue(out var message, out var priority))
{Console.WriteLine($"{message}, {priority.priority}, {priority.time}");
}

输出示例如下:

由上面的结果可以看出来,在 priority一样的情况下,我们会先处理时间较小的消息,也可以根据自己的需要进行定制排序方式,自定义 Priority 比较逻辑即可,上面的自定义优先级比较代码如下:
internal class DateTimePriorityComparer : IComparer<(DateTime time, int priority)>
{public int Compare((DateTime time, int priority) x, (DateTime time, int priority) y){var priorityComparison = x.priority.CompareTo(y.priority);if (priorityComparison != 0) return priorityComparison;return x.time.CompareTo(y.time);}
}

Rank

在很多做排行榜的应用中也可以使用 PriorityQueue 来实现,比如我们来做一个学生成绩的排名

来看下面的示例代码:

var list = new List<(string name, int score)>
{("Mike", 99),("Ming", 100),("Jane", 96),("Yi", 94),("Harry", 90),
};var priorityQueue = new PriorityQueue<string, int>();
priorityQueue.EnqueueRange(list);Console.WriteLine("--Unordered:");
foreach (var item in priorityQueue.UnorderedItems)
{Console.WriteLine($"Name:{item.Element}, score:{item.Priority}");
}Console.WriteLine("--Ordered:");
while (priorityQueue.TryDequeue(out var name, out var score))
{Console.WriteLine($"Name:{name}, score:{score}");
}Console.WriteLine("-----TOP 3");
priorityQueue = new PriorityQueue<string, int>(new High2LowComparer());
priorityQueue.EnqueueRange(list);
var rank = 0;
while (rank++ < 3 && priorityQueue.TryDequeue(out var name, out var score))
{Console.WriteLine($"Rank({rank}):Name:{name}, score:{score}");
}

上面的 list 就是一个成绩清单,随便写了几个测试数据,通过 PriorityQueueUnorderedItems 我们可以拿到排序之前的数据,也是我们加入队列(Enqueue)的顺序,默认的比较是小的在前,也就是成绩低的在前,那我们想按从大到小排序的话就需要自定义比较方式。

上面的 High2LowComparer 就是一个自定义的比较,其实就是把比较的结果取了一个反,代码如下:

internal class High2LowComparer : IComparer<int>
{public int Compare(int x, int y){return y.CompareTo(x);}
}

上面的输出结果如下:

More

Redis 里有一个 zset(sortedSet) 类型的数据也可以做类似的事情,但是 zset 和 PriorityQueue 还是有一些不同的,zset 是一个 set,是一个自动去重的集合,而 PriorityQueue 还是一个 Queue 不会去重,zset 可以修改对应元素的 priority(score),但是 PriorityQueue 目前不支持修改元素对应的优先级

PriorityQueue  可以解决我们的一些问题,但是有一些使用要注意的地方:

  1. 首先如果 Priority 是一样的话,输出的顺序是有可能不一样的,这是由它内部的实现算法决定的,不能严格的保证顺序

  2. PriorityQueue 是非线程安全的,需要注意线程安全问题

  3. PriorityQueue 中的 Peek 方法只会获取 queue 里即将出队的元素,但是不会从队列中移除这个元素

References

  • https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-2/

  • https://github.com/dotnet/runtime/blob/v6.0.0-preview.2.21154.6/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs

  • https://github.com/WeihanLi/SamplesInPractice/blob/master/net6sample/PriorityQueueSample/Program.cs

.NET6 中的 PriorityQueue相关推荐

  1. .NET6中关于Minimal API的简单使用

    微信公众号:趣编程ACE 收集并分享日常的.NET实战开发技巧,源码获取关注后回复 源码; **如果觉得本公众号对您有帮助,欢迎关注 本文来自社区群粉丝投稿 .NET6中关于Minimal API的简 ...

  2. 【C#/.NET】.NET6中全局异常处理

    微信公众号:趣编程ACE 关注可了解每日一更的.NET日常实战开发技巧,欢迎公众号留言开发 获取源码; .NET6中全局异常处理 异常处理是我们在程序开发中不可或缺的一环,下文我将会结合程序Sampl ...

  3. java queue size_Java中的PriorityQueue size() 方法 - Break易站

    Java.util.PriorityQueue.size()方法用于获取PriorityQueue的大小或PriorityQueue中存在的元素数. 句法: Priority_Queue.size() ...

  4. 使用.Net6中的System.Text.Json遇到几个常见问题及解决方案

    前言 以前.NetCore是不内置JSON库的,所以大家都用Newtonsoft的JSON库,而且也确实挺好用的,不过既然官方出了标准库,那更方便更值得我们多用用,至少不用每次都nuget安装Newt ...

  5. Java中的PriorityQueue优先级队列

    以前的博客中介绍过队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,此时出队列时需要优先级高的元素先出队列,这个时候传统的队列显然不能胜任,Java中有一个新的实现类继 ...

  6. net6中webapi配置

    目标: 采用webgl访问webapi,通过webapi访问数据库,webgl发布后,总是提示ConnectionError,通过F12发现,数据请求发送成功,没有返回数据. webapi配置 内容: ...

  7. 细聊.NET6 ConfigurationManager的实现

    前言 友情提示:建议阅读本文之前先了解下.Net Core配置体系相关,也可以参考本人之前的文章<.Net Core Configuration源码探究 [1]>然后对.Net Core的 ...

  8. .NET6之MiniAPI(一):开始Mini API

    Mini API之前的官方.net web框架,都是偏重的,不像其他语言,如go,python,或基于c#的nancy,都是简洁方式来开启web之旅的.所以有小伙伴就吐槽.net基于web的不友好性, ...

  9. .NET6又出新版本,新增这几个大杀器!

    .NET6 Preview4终于发布了,作为第4个预览版,伴随着Build2021发布的,器更新内容也是非常丰富的.推荐关注的有以下11项: 引入最小 API 异步流 HTTP 日志中间件 新项目中使 ...

最新文章

  1. Tomcat单向Https验证搭建,亲自实现与主流浏览器、Android/iOS移动客户端安全通信
  2. T-SQL: 17 个与日期时间相关的自定义函数(UDF),周日作为周的最后一天,均不受 @@DateFirst、语言版本影响...
  3. 0607am抽象类接口析构方法tostring小知识点
  4. GridView里面的HyperLink和ButtonField操作总结
  5. 记事本 换行符_30年后终更新!新一代Win10记事本详细体验
  6. SDWebImage 4 0 迁移指南
  7. 一个简单的Makefile模板
  8. PAT练习题:D进制的A+B(C++)
  9. Timestamp 与 Date 变量绑定与Oracle的自动分区
  10. 如何在手机上打开xmind文件_xmind在手机上怎么操作
  11. Leetcode 俄罗斯套娃信封问题
  12. mac搭建c语言开发环境
  13. 云服务器虚拟化安全,云计算中的安全云服务的资源池化和虚拟化(1)
  14. win10微软图标点击无反应_双击电脑桌面图标没反应,win10双击图标没反应
  15. 关于Windows-Linux双系统的启动引导
  16. 算法 数论 素数(质数)
  17. 手把手教你脑电波采集及信号处理分析
  18. CSK6开发分享2-视觉开发套件驱屏魔改篇
  19. POI之Excel简单导入
  20. AWS 容器三大新品:K8s 发行版,免费镜像库和 “Game Changer”AWS Proton

热门文章

  1. 斑马无线打印服务器,如何设置斑马打印机无线WiFi
  2. plsql如何执行存储过程_如何理解Spark应用的执行过程
  3. MapReduce 2 中一些基础数据类型
  4. 论DATASNAP远程方法支持自定义对象作参数
  5. 为operamasks增加HTML扩展方式的组件调用
  6. SQL Server索引进阶第十篇:索引的内部结构
  7. TC的文件拷贝/移动
  8. vista 中php4, php5 共存
  9. 惠普m1005连接电脑步骤_电脑连接电视机详细步骤方法图文
  10. Unity3D学习笔记之九为场景添加细节(二)