前言最近把Python写的数据采集平台往.Net Core上迁移 , 原本的采集任务使用多进程+线程池的方式来加快采集速度,使用Celery作为异步任务队列兼具定时任务功能,这套东西用着还行,但反正就折腾嘛,直接上C#~
本文记录 Hangfire 在实际应用里的用法,我发现网络上找到的大部分文章都是用 Hangfire 的异步任务输出个 Hello World,然后就没了 。我实在不知道这样的文章写了有什么意义??除了浪费看的人的时间之外,还浪费自己写文章的时间…….NetCore作为一个高性能的平台,自然不可能输给Python,不过我不想造轮子了(菜),找个现成的方案来用,免得踩坑~
先是调研了一下.NetCore目前的生态,发现有几个选择:
- FreeScheduler
- Quartz.net
- Hangfire
然后在 Quartz.net 和 Hangfire 两者中,我选择了后者,原因是我之前做 CrawlCenterNet 项目的时候用过 Hangfire,还挺好用的,且带有一个简单的 dashboard,比较直观~
那么就开始吧~
关于后端的选择这里的后端指的是任务队列的存储后端,也就是 Hangfire 文档中写的 Storage 。
看了一下官网,大部分关系型非关系型数据库都是可以的,那我就放心了 。由于目前生产环境在使用 Oracle 数据库,所以一开始我选择了 Oracle 作为 Storage,但是在同时开到2000多个任务的时候报错了,看了下原因是表空间不足,是 Oracle 的问题…
所以为了性能和稳定性,我弃坑了,接着尝试了 SQLite (仅作为本地测试),结果发现配置里面定义了 Connection String 但它不理我,直接把这个 Connection String 作为数据库的名称了 , 无语… 这样就没办法把 SQLite 数据库设置为异步模式 , 那速度就直接乌龟爬了…
再次弃坑… 这次直接上 Redis 了,为了提高性能,舍弃持久化能力~ Redis也没让我失望,几千个任务压根不带眨眼的,nice~
数据采集代码Hangfire 组件不是一开始就引入的,这里先上最基本的数据采集代码,后面的介绍才能更清楚~
关键的代码在
Services/CrawlService.cs
文件中public class CrawlService {// 依赖注入一些服务private readonly IBaseRepository<Proc> _repo;public async Task CrawlAllProc() {for(var i=1; i<2000; i++) {await CrawlProcList(i);}}public async Task CrawlProcList(int page) {// 具体代码省略了var procList = ; //...foreach (var proc in procList) {await CrawlProc(proc);}}public async Task CrawlProc(Proc proc) { }}
然后,当启动采集任务的时候,直接去调用 CrawlAllProc
方法,这样就开始一页一页采集 , 每页又有很多的 Proc
数据,全都采集下来 。上面的代码用的是
await
,会等待异步方法完成,速度很慢,去掉 await
,在新线程中执行任务,不等待其结束,不过问题也很明显,如果出错了很难调试,这样就不好保证系统的稳定性 。接下来我们用 Hangfire 来改造 。
安装 Hangfire本项目用到了以下依赖:
- Hangfire.Core
- Hangfire.AspNetCore
- Hangfire.Redis.StackExchange
注册服务为了跟后面的内容区分,这里先来官方的例子
注册服务:
services.AddHangfire(configuration => configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_170).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings()// 根据实际使用的 Storage 来注册.UseRedisStorage();services.AddHangfireServer();
添加中间件:app.UseHangfireDashboard();
简单使用Hangfire 注册的时候默认是单例模式,所以在任意代码中使用其静态方法就能添加异步任务或者定时任务 。异步任务:
BackgroundJobs.Enqueue(() => Console.WriteLine("Hello world!"));
定时任务:Hangfire的定时任务叫做 recurrent tasks,我之前一般习惯叫 scheduled task,一开始差点找不到文档~
以下代码添加一个每天执行一次的任务 , 如果需要其他时间 , 可以自定义后面的 Cron 参数 , 具体自行研究 Cron 语法~
RecurringJob.AddOrUpdate("easyjob", () => Console.Write("Easy!"), Cron.Daily);
正经使用OK , 终于进到正文正如我一开始说的 , 前面介绍的用法是远远不够的,如果只是介绍个 Hello World,那也没必要专门写篇文章了…
推荐阅读
- 【疫情动态条形图】用Python开发全球疫情排名动态条形图bar_chart_race
- 初等数论学习笔记 III:数论函数与筛法
- 前端程序员学习 Golang gin 框架实战笔记之一开始玩 gin
- 驱动开发:通过Async反向与内核通信
- gRPC+Protocol Buffer Go微服务实战 - 用户服务开发
- WPF开发经验-实现自带触控键盘的TextBox
- 前端三件套 HTML+CSS+JS基础知识内容笔记
- 驱动开发:通过ReadFile与内核层通信
- 三十六 Java开发学习----SpringBoot三种配置文件解析
- 《Vision Permutator: A Permutable MLP-Like ArchItecture For Visual Recognition》论文笔记