一、IHostedService
1、概述
想要实现后台任务可以实现IHostedService接口或者直接继承BackgroundService抽象类。
IHostedService接口是托管服务接口,在Microsoft.Extensions.Hosting命名空间下面,有两个接口方法:
StartAsync(CancellationToken) :当应用程序主机准备好启动服务时触发该方法
StopAsync(CancellationToken):当应用程序主机执行正常关闭时触发该方法。
2、首先需要介绍下Timer
public Timer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period);
TimerCallback callback
:这是一个委托,指向当定时器触发时要调用的方法。该方法必须有一个object
类型的参数,该参数是你传递给Timer
构造函数中的state
对象。object state
:这是一个传递给callback
委托的参数。你可以通过这个参数传递任何你需要的数据给callback
方法。如果不需要传递任何数据,可以传递null
。TimeSpan dueTime
:这是定时器在首次触发之前应该等待的时间。如果你希望定时器立即开始(即,尽快触发第一次),可以将此值设置为TimeSpan.Zero
。如果你希望定时器在将来的某个时间点触发,可以指定一个表示延迟时间的TimeSpan
。TimeSpan period
:这是定时器连续触发之间的时间间隔。如果你不希望定时器周期性地触发(即,只触发一次),可以将此值设置为Timeout.InfiniteTimeSpan
。
public bool Change(TimeSpan dueTime, TimeSpan period);
public bool Change(long dueTime, long period);
- 第一个
Change
方法接受两个TimeSpan
类型的参数,与构造函数中的dueTime
和period
参数相同。 - 第二个
Change
方法接受两个long
类型的参数,这些参数是dueTime
和period
的毫秒数表示。这对于需要精确控制时间间隔(尤其是当时间间隔非常短或需要精确到毫秒时)很有用。
3、用法示例
public class MyIHostedService : IHostedService, IDisposable
{
private Timer _timer;
private void DoWork(object state)
{
Console.WriteLine("DoWork正在运行"+DateTime.Now.ToString());
}
public Task StartAsync(CancellationToken cancellationToken)
{
Console.WriteLine("StartAsync执行前");
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(10));//立即执行一次,每10秒执行一次
Console.WriteLine("StartAsync执行后");
return Task.CompletedTask;// 立即返回Task.CompletedTask,因为StartAsync应该尽快返回
}
public Task StopAsync(CancellationToken cancellationToken)
{
Console.WriteLine("StopAsync执行前");
_timer?.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);//停止Timer
Console.WriteLine("StopAsync执行后");
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();//释放Timer资源
}
}
//program.cs
//注入IHostedService后台服务
builder.Services.AddHostedService<MyIHostedService>();
实现效果
二、BackgroundService
BackgroundService是一个抽象类,这个类实现 IHostedService 接口,并将包含后台任务的具体代码逻辑。该抽象类有一个抽象方法:
- ExecuteAsync(CancellationToken): 子类需要重写该方法以执行具体的任务处理
1、基础用法示例
public class MyBackgroundService : BackgroundService
{
// 当BackgroundService启动时,ExecuteAsync方法将被调用
// stoppingToken用于监听取消请求
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
Console.WriteLine("执行前");
await Task.Delay(10000, stoppingToken);//模拟工作耗时
Console.WriteLine("执行中");
Console.WriteLine("执行后");
}
catch(Exception ex)
{
Console.WriteLine(ex);
await Task.Delay(TimeSpan.FromHours(1), stoppingToken);//出现错误,则过一个小时再次执行
}
}
}
}
//program.cs
builder.Services.AddHostedService<MyBackgroundService>();
控制台
2、实例
public class HostingServices : BackgroundService
{
private readonly ClearDataForP_TERMINAL_HT _dataClearer;
public HostingServices(ClearDataForP_TERMINAL_HT _dataClearer)
{
this._dataClearer = _dataClearer;
}
//每隔一小时清除一次数据
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
await _dataClearer.ClearData();//是一个删除数据的方法,通过依赖注入进来
var nextRunTime = DateTime.Now.AddHours(1);//每一个小时执行一次
var delayTime = nextRunTime - DateTime.Now;
await Task.Delay(delayTime, stoppingToken);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message.ToString());
await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
}
}
}
}
三、QuartZ.Net
1、概述
Quartz.NET 里有三个非常重要的概念:任务,触发器 和 调度器,对应着 Job,Trigger 和Scheduler
1.1、Job 表示一个你需要被执行的任务,任务中可以写上你的业务逻辑代码,Job 就是一个实现了 IJob 接口的子类。
1.2、Trigger 通常用于指定一个 job 是如何被调度的? 什么意思呢? 比如说:这个job是按天执行? 还是按小时执行?还是按秒执行?值得注意的是因为支持了 Cron 表达式,还能够实现更加超级复杂的调度逻辑。
1.3、Scheduler 通常按照你预先设置的调度规则将 job 丢给它的任务队列,并按照 trigger 规则轮询然后执行任务。
2、简单实现
2.1、nuget包 Quartz
2.2、自定义类
using Quartz;
using Quartz.Impl;
namespace IHostedService_lianxi
{
public class MyQuartZ:IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
//创建调度器工厂
var factory = new StdSchedulerFactory();
//从工厂中获取调度器
IScheduler scheduler = await factory.GetScheduler();
//定义作业详情
IJobDetail job = JobBuilder.Create<MyJob>()
.WithIdentity("myjob", "group1")
.Build();
//定义触发器
//1、定义一个简单触发器
var trigger1 = TriggerBuilder.Create()
.WithIdentity("myTrigger", "group1")
.WithSimpleSchedule(o =>
{
o.WithRepeatCount(3)//循环次数
.WithIntervalInSeconds(10);//每10秒执行一次
}).Build();
//2、创建Cron触发器(Cron触发器比简答触发器更加强大)
var trigger2 = TriggerBuilder.Create()
.WithCronSchedule("* * * * * ? *")
.Build();
//告诉调度器去调度我们的作业
await scheduler.ScheduleJob(job, trigger1);
//启动调度器
await scheduler.Start();
}
public async Task StopAsync(CancellationToken cancellationToken)
{
//结束时调用的
}
}
//自定义我的job
public class MyJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
Console.WriteLine("MyJob执行中");
await Task.Delay(5000);
//return Task.CompletedTask;
}
}
}
//program.cs
//注入IHostedService后台服务
builder.Services.AddHostedService<MyQuartZ>();
控制台