月度归档:2023年02月

C#神器”BlockingCollection”类实现C#神仙操作

前言

如果你想玩转C# 里面多线程,工厂模式,生产者/消费者,队列等高级操作,就可以和我一起探索这个强大的线程安全提供阻塞和限制功能的C#神器类

BlockingCollection简单介绍

微软介绍地址:https://learn.microsoft.com/zh-cn/dotnet/standard/collections/thread-safe/blockingcollection-overview
BlockingCollection 是一个线程安全集合类,可提供以下功能:

  1. 实现制造者-使用者模式
  2. 通过多线程并发添加和获取项
  3. 可选最大容量
  4. 集合为空或已满时通过插入和移除操作进行阻塞
  5. 插入和移除“尝试”操作不发生阻塞,或在指定时间段内发生阻塞
  6. 封装实现 IProducerConsumerCollection 的任何集合类型
  7. 使用取消标记执行取消操作
  8. 支持使用 foreach(在 Visual Basic 中,使用 For Each)的两种枚举:1. 只读枚举,2. 在枚举项时将项移除的枚举

起手式

BlockingCollectionblockingCollection = new(1);

  • new 操作符里面的数字是实现了可选最大容量,超出就线程阻塞了,程序一直卡在哪里

先来个开胃菜 => 三句代码实现线程阻塞

BlockingCollection<int> blockingCollection = new(1);
blockingCollection.Add(1);
blockingCollection.Add(2);

说明:因为限制队列只能插入一条,第一条没有消费掉,所以一直卡在插入第二条程序不会往下继续运行实现了集合为空或已满时通过插入和移除操作进行阻塞

正式开始前先分享一些多线程的知识点

Task类简单介绍

Task 表面上是Thread但却是对ThreadPool的封装,控制和扩展性很强,对线程的延续,阻塞,取消,超时,比传统的Thread和ThreadPool强

Queue类简单介绍

队列(Queue)代表了一个先进先出的对象集合。当您需要对各项进行先进先出的访问时,则使用队列。当您在列表中添加一项,称为入队,当您从列表中移除一项时,称为出队

接下来进入实际使用场景

场景一: 生产者=> 消费者

建议代码还是要动手实现一下,不然体会不到一边生产数据,同时还能取数据的神仙操作

int count = 0 ;
BlockingCollection<string> blockingCollection = new(1);
//生产者
Task.Factory.StartNew(() =>
{
 while (true)
 {
    blockingCollection.Add("String: " + count);
    count++;
    if (count > 10)
    {
     blockingCollection.CompleteAdding();
    }
 }
});

//消费者
Task.Factory.StartNew(() =>
{
 foreach (var element in blockingCollection.GetConsumingEnumerable())
 {
  Thread.Sleep(1000);
  ("Work: " + element).Dump();//Dump 为工具Linq的功能
 }
});

上面的代码中这个方法GetConsumingEnumerable很重要,它可以在BlockingCollection集合有数据的时候取数据,没有的话停止取,可以达到监测的效果

这个案例实现了如下功能:

  1. 多线程并发添加和获取项
  2. 生产者和消费者模式
  3. 使用取消标记执行取消操作(让生产者知道我们已经不需要你工作了)

生产者/消费者输出结果

Work: String: 0
Work: String: 1
Work: String: 2
Work: String: 3
Work: String: 4
Work: String: 5
Work: String: 6
Work: String: 7
Work: String: 8
Work: String: 9
Work: String: 10

场景二: 实现队列FIFO(先进先出),LIFO(先进后出)

 //先进先出(FIFO)
 BlockingCollection<int> bc = new(new ConcurrentQueue<int>());
 bc.Add(1);
 bc.Add(2);
 bc.CompleteAdding();

 //先进后出(LIFO)
 BlockingCollection<int> bc2 = new(new ConcurrentStack<int>());
 bc2.Add(1);
 bc2.Add(2);
 bc2.CompleteAdding();

 bc.Take().Dump("bc1:");
 bc2.Take().Dump("bc2:");

队列输出结果

bc :1 
bc2: 2

这个简单的案例是想介绍一下其实:BlockingCollection也可以实现队列的功能

以上就是本期的全部内容啦谢谢大家看到这里

作者 => 百宝门瞿佑明

多人协同开发,git workflow 提高团队协作能力

—-by:刘坚 百宝门-前端组

👧🏻集美们,还在为工作多年而只会使用简单的git指令被质疑是假简历而烦恼吗😑. Don’t worry!

|| 今天给带来大家一个git攻略指南😘.成为大手子,🥰参与开源大项目指日可待👩🏻‍💻👩🏻‍💻👩🏻‍💻. 😭.

Git

这是git的官方文档直通车🚃:

GitHub.com Help Documentation

容我随手截图:

可能对于英语成绩不好的小姐妹来说,文档是相当的不友好.

头晕了,幻痛了(读书的回忆全都回来了).

全是英语,宝宝难受,人生艰难😑😮‍💨.

但,这些都是小问题!

我们只要轻轻的滑动一下鼠标,关注这块就可以了🙈:

左边就是日常的git指令设置SSH之类的老生常谈的操作.

然后看右边的About pull request这就是需要介绍的.

你只需要了解四条最常规的git指令就ok😋.

// 添加文件到暂存区
git add .

// 设置提交的说明
git commit -m "feat: xxx"

// 拉去远程仓库代码
git pull origin <branch name>

// 推送远程仓库代码
git push origin <branch name>

git workflow

一种基于gitflow的工作方式,这种工作方式主要用于: 管理新功能😎,发布新特性📢,以及维护👨🏻‍🔧👩🏻‍🔧等.

大部分人都使用github都只是单纯的用它来储存代码🤪,但是,github上⭐上万的repo.参与代码的贡献者们有上千上万🤨他们该如何管理各种代码冲突🤪和版本发布🤪呢?

这便是gitflow: 根据不同的工作特性来创建不同的分支进行定义:

  1. master 主分支
  2. feature 新分支
  3. hotfix 热补丁分支
  4. fix 修复bug分支
  5. 等..

那么,所有基于master衍生出来的分支该如何管理呢❓❓❓

PR便是管理这些gitflow的屠龙宝刀❗❗❗

Pull Request

官网介绍:

简而言之🚴🏻‍♂️: 当你在自己的feature(fix.hotfix)分支或者派生仓库上完成功能开发,并入主分支(稳定版本)或者主仓库的一个可视化请求.

现在,找一个项目开启一次PR完成流程🧐.

找项目

👨🏻随随便便在网上找一个大型开源项目🧑🏻‍🔧然后准备动手⚠️,准备动手⚠️,准备动手⚠️

百度的深度学习的repo. 现在对他发一个最简单的PR.

贴上地址:

https://github.com/PaddlePaddle/Paddle.

修改错别字🙈

fork repo

出现如下界面:

然后,随便找个错别字更正🙉:

push到自己fork的仓库,然后创建PR,如下图所示:

创建成功:

在创建成功之后,大型项目仓库都有分支保护代码审查(CodeReview) .

等待审查通过,成功你就是 大型开源项目的代码贡献者了🌈.

用AngleSharp & LINQPad抓取分析博客园排行榜

AngleSharp简单介绍

  1. AngleSharp 是一个 .NET 库
  2. 使您能够解析基于尖括号的超文本,如HTML、SVG、MathML、XML
  3. AngleSharp的一个重要方面是CSS也可以解析
  4. 同时还是开源,免费的

Github: https://github.com/AngleSharp/AngleSharp
使用文档: https://anglesharp.github.io/

开发工具的推荐LINQPad

介绍:一个小巧,打开秒速,随时能写C#,不至于灵感快速流失的小工具
下载地址:https://www.linqpad.net/
有免费版,基本功能已经够用。我们公司买了它的Premium版。

AngleSharp 代码实操

实操前一些分享一些C#的知识点

如何快速发送网络请求获取到数据呢?

可以用如下:
1、HttpWebRequest
2、WebClient
3、HttpClient
4、RestSharp
5、Flurl

本期重点用HttpClient来实现

起手式

引用NuGet包: Install-Package AngleSharp

使用场景案例

  1. 获取博客园排行榜的Html并且解析
IConfiguration config = Configuration.Default.WithDefaultLoader();
string address = "https://www.cnblogs.com/aggsite/SideRight";
IBrowsingContext context = BrowsingContext.New(config);
IDocument document = await context.OpenAsync(address);
IHtmlCollection<IElement> side_right = document.QuerySelectorAll("div");

side_right.Select(m => new { 
        title = m.QuerySelector(".card-title a")?.TextContent,
        url = m.QuerySelectorAll("ul li").Select(x => x.TextContent)
       })
       .Where(x => x.title != null)
       .Dump();

通过上面代码快速就能分析且快速抓取博客园的排行榜,简单,快速,高效 代码少,有没有觉得Linq语法糖配合请求一些框架的强大呢,朋友们

效果图

既然都能抓取数据了,接下来就是爬虫最重要的分析啦

2.分析博客园每天什么时候发博客看的人数最多,点赞的人数最多,星期几发文章多,哪个大佬发文章多

获取数据的方法

通过HttpClient加上Linq加上AngleSharp实现请求获取Hmtl => 保存Json => 分析Json 生成有价值的图表

public void GetData()
{
 var http = new HttpClient();
 var parser = new HtmlParser();

 File.WriteAllText(@"C:\Users\QYM\Desktop\OfficFile\BlogData.json", JsonConvert.SerializeObject(Enumerable.Range(1, 200)
     .AsParallel()
     .AsOrdered()
     .SelectMany(page =>
     {
      var content = new StringContent(JsonConvert.SerializeObject(new
      {
       CategoryId = "808",
       CategoryType = "SiteHome",
       ItemListActionName = "AggSitePostList",
       PageIndex = $"{page}",
       ParentCategoryId = "0",
       TotalPostCount = "4000"
      }), Encoding.UTF8, "application/json");

      var resp = http.PostAsync("https://www.cnblogs.com/AggSite/AggSitePostList", content).Result;

      var document = parser.ParseDocument(resp.Content.ReadAsStringAsync().GetAwaiter().GetResult());


      return document?.QuerySelectorAll("article").Select(pageContext =>
      {
       return new
       {
        Url = pageContext.QuerySelector(".post-item-text a").GetAttribute("href").Trim(),
        Title = pageContext.QuerySelector(".post-item-text a").TextContent.Trim(),
        Context = pageContext.QuerySelector(".post-item-text p").TextContent.Trim(),
        Name = pageContext.QuerySelector("footer a").TextContent.Trim(),
        DateTime = DateTime.Parse(pageContext.QuerySelector("footer .post-meta-item").TextContent),
        LookOK = pageContext.QuerySelector("footer .post-meta-item+a span").TextContent.Trim(),
        LookPerson = pageContext.QuerySelector("footer .post-meta-item+a+a+a span").TextContent.Trim()
       };
      });
     }), Newtonsoft.Json.Formatting.Indented));
}

效果图

获取博客园200页数据

读取数据并且调用LinqPad 自带的Chart图表方法进行分析

public void ReadData()
{
 var data = JsonConvert.DeserializeObject<List<BlogJsonData>>(File.ReadAllText(@"C:\Users\QYM\Desktop\OfficFile\BlogData.json"));

 Util.Chart(data
 .GroupBy(x => x.DateTime.Hour)
 .Select(x => new { Hour = x.Key, ViewCount = 1.0 * x.Sum(v => v.LookPerson) })
 .OrderByDescending(x => x.Hour),
 x => x.Hour,
 y => y.ViewCount, Util.SeriesType.Bar).Dump("时间段观看人数最多");

 Util.Chart(data
 .GroupBy(x => x.DateTime.Hour)
 .Select(x => new { Hour = x.Key, ViewCount = 1.0 * x.Sum(v => v.LookOk) })
 .OrderByDescending(x => x.Hour),
 x => x.Hour,
 y => y.ViewCount, Util.SeriesType.Bar).Dump("时间段点赞人数最多");

 Util.Chart(data
  .GroupBy(x => x.DateTime.DayOfWeek)
  .Select(x => new { WeekDay = x.Key, ArticleCount = x.Count() })
  .OrderBy(x => x.WeekDay),
 x => x.WeekDay.ToString(),
 y => y.ArticleCount, Util.SeriesType.Bar).Dump("星期几发文章最多");

 Util.Chart(data
  .GroupBy(x => x.Name)
  .Select(x => new { UserName = x.Key, ArticleCount = x.Count() })
  .OrderByDescending(x => x.ArticleCount)
  .Take(9),
 x => x.UserName,
 y => y.ArticleCount,  Util.SeriesType.Bar).Dump("哪个大佬发文章比较多");

}

效果图

源文件Json

分析数据的实体

public class BlogJsonData
{
 public string Url { get; set; }
 public string Title { get; set; }
 public string Context { get; set; }
 public string Name { get; set; }
 public DateTime DateTime { get; set; }
 public int LookOk { get; set; }
 public int LookPerson {get;set;}
}

接下来就是见证奇迹的时候,通过分析抓取到html,保存成Json分析出一些意想不到的图表

效果图

  1. 时间段观看人数最多?

看来博客园一般查看人数最多的是9点->10点,说明哈哈哈,果然大家早上都是喜欢关注编程的大事呀

  1. 时间段点赞人数最多?

果然早起的鸟儿有虫吃,如果想要博客点赞高,那就必须早上九点 -> 10点 抓住阅读高峰期,菜鸟收获高赞,得到很多人的认可

  1. 星期几发文章最多?

看来星期一到星期五中发博客最多的星期一和星期二,最不想上班的两天最适合用来灵感创作写文字

  1. 哪个大佬发文章比较多?

目测近期京东云开发者对博客园贡献很大,看了一下,质量都是很高的文章,极力推荐