在現(xiàn)代應(yīng)用程序開(kāi)發(fā)中,定時(shí)任務(wù)是不可或缺的組成部分。無(wú)論是數(shù)據(jù)同步、郵件發(fā)送、系統(tǒng)維護(hù),還是定期生成報(bào)告,都需要可靠的定時(shí)任務(wù)支持。本文將介紹如何使用 Cronos,一個(gè)強(qiáng)大的 .NET 任務(wù)調(diào)度庫(kù),通過(guò)控制臺(tái)應(yīng)用程序來(lái)實(shí)現(xiàn)定時(shí)任務(wù)。
什么是 Cronos? Cronos 是一個(gè)輕量級(jí)的 .NET 庫(kù),用于解析和計(jì)算 CRON 表達(dá)式。它允許開(kāi)發(fā)者使用熟悉的 CRON 語(yǔ)法來(lái)安排任務(wù)的執(zhí)行時(shí)間。Cronos 的主要特點(diǎn)包括:
支持標(biāo)準(zhǔn) CRON 語(yǔ)法 :包括秒、分、時(shí)、日、月和星期。
高性能 :采用高效的算法解析 CRON 表達(dá)式。
靈活性 :可用于各種 .NET 程序,包括控制臺(tái)、Web 應(yīng)用和服務(wù)。
環(huán)境準(zhǔn)備 在開(kāi)始之前,請(qǐng)確保您已安裝以下環(huán)境:
安裝 Cronos 包 在項(xiàng)目中安裝 Cronos 包:
dotnet add package Cronos
實(shí)現(xiàn)定時(shí)任務(wù) 接下來(lái),我們將創(chuàng)建一個(gè)通用的定時(shí)任務(wù)基類(lèi),使用 Cronos
來(lái)解析 CRON 表達(dá)式,并使用 Task.Delay
來(lái)等待下一個(gè)執(zhí)行時(shí)間。
創(chuàng)建基礎(chǔ)定時(shí)任務(wù)類(lèi) using Cronos;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace AppCron { public abstract class CronJob { private readonly CronExpression _expression; private readonly TimeZoneInfo _timeZoneInfo; protected CronJob (string cronExpression, TimeZoneInfo timeZoneInfo = null) { _expression = CronExpression.Parse(cronExpression, CronFormat.IncludeSeconds); // 指定格式為包含秒 _timeZoneInfo = timeZoneInfo ?? TimeZoneInfo.Local; } public async Task StartAsync (CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { var next = _expression.GetNextOccurrence(DateTimeOffset.Now, _timeZoneInfo); if (next.HasValue) { var delay = next.Value - DateTimeOffset.Now; if (delay.TotalMilliseconds > 0 ) { await Task.Delay(delay, cancellationToken); } if (!cancellationToken.IsCancellationRequested) { await ExecuteAsync (cancellationToken) ; } } else { break ; } } } protected abstract Task ExecuteAsync (CancellationToken cancellationToken) ; } }
示例任務(wù):打印消息 讓我們創(chuàng)建一個(gè)示例任務(wù),每分鐘打印一條消息。
using System;using System.Threading;using System.Threading.Tasks;public class PrintMessageJob : CronJob { public PrintMessageJob () : base ("0 * * * * *" ) // 每分鐘的第 0 秒執(zhí)行 { } protected override Task ExecuteAsync (CancellationToken cancellationToken) { Console.WriteLine($"當(dāng)前時(shí)間:{DateTime.Now}" ); return Task.CompletedTask; } }
在主程序中運(yùn)行任務(wù) 修改 Program.cs
文件:
using System;using System.Threading;using System.Threading.Tasks;namespace CronosDemo { class Program { static async Task Main (string [] args) { var cts = new CancellationTokenSource(); Console.CancelKeyPress += (sender, eventArgs) => { Console.WriteLine("正在退出..." ); cts.Cancel(); eventArgs.Cancel = true ; }; var job = new PrintMessageJob(); await job.StartAsync(cts.Token); } } }
每分鐘,程序?qū)⑤敵霎?dāng)前時(shí)間。
更多示例 示例 1:每隔 5 秒執(zhí)行任務(wù) 修改任務(wù)的 CRON 表達(dá)式:
public class PrintMessageJob : CronJob { public PrintMessageJob () : base ("*/5 * * * * *" ) // 每隔 5 秒執(zhí)行 { } // 其余代碼保持不變 }
示例 2:每天凌晨 2 點(diǎn)執(zhí)行數(shù)據(jù)備份 創(chuàng)建一個(gè)新的任務(wù)類(lèi):
using System;using System.Threading;using System.Threading.Tasks;public class DataBackupJob : CronJob { public DataBackupJob () : base ("0 0 2 * * *" ) // 每天凌晨 2 點(diǎn)執(zhí)行 { } protected override async Task ExecuteAsync (CancellationToken cancellationToken) { Console.WriteLine("開(kāi)始數(shù)據(jù)備份..." ); // 模擬備份操作 await Task.Delay(2000 , cancellationToken); Console.WriteLine("數(shù)據(jù)備份完成!" ); } }
修改 Program.cs
,使其可以同時(shí)管理多個(gè)任務(wù):
using System;using System.Threading;using System.Threading.Tasks;using System.Collections.Generic;namespace CronosDemo { class Program { static async Task Main (string [] args) { var cts = new CancellationTokenSource(); Console.CancelKeyPress += (sender, eventArgs) => { Console.WriteLine("正在退出..." ); cts.Cancel(); eventArgs.Cancel = true ; }; var jobs = new List<CronJob> { new PrintMessageJob(), new DataBackupJob() }; var tasks = new List<Task>(); foreach (var job in jobs) { tasks.Add(job.StartAsync(cts.Token)); } await Task.WhenAll(tasks); } } }
理解 CRON 表達(dá)式 CRON 表達(dá)式由空格分隔的六個(gè)字段組成:
┌──────── 秒 (0 - 59) │ ┌────── 分鐘 (0 - 59) │ │ ┌──── 小時(shí) (0 - 23) │ │ │ ┌── 日期 (1 - 31) │ │ │ │ ┌ 月份 (1 - 12) │ │ │ │ │ ┌─ 星期 (0 - 6) [星期日=0] │ │ │ │ │ │ * * * * * *
常用示例 * * * * * *
:每秒執(zhí)行
0 * * * * *
:每分鐘的第 0 秒執(zhí)行
0 0 * * * *
:每小時(shí)的第 0 分 0 秒執(zhí)行
0 0 2 * * *
:每天凌晨 2 點(diǎn)執(zhí)行
0 */5 * * * *
:每隔 5 分鐘執(zhí)行
0 0 9-17 * * 1-5
:周一至周五的 9 點(diǎn)至 17 點(diǎn),每小時(shí)執(zhí)行一次
注意事項(xiàng)和最佳實(shí)踐 時(shí)區(qū)設(shè)置 :確保任務(wù)的執(zhí)行時(shí)間與預(yù)期的時(shí)區(qū)一致。默認(rèn)情況下,Cronos 使用本地時(shí)區(qū)。
異常處理 :在任務(wù)執(zhí)行過(guò)程中,要捕獲并處理可能的異常,防止任務(wù)崩潰。
任務(wù)間隔 :避免使用過(guò)短的間隔(如每秒執(zhí)行),以免對(duì)系統(tǒng)造成壓力。
資源釋放 :如果任務(wù)使用了文件、網(wǎng)絡(luò)連接等資源,確保在任務(wù)完成后正確釋放。
小結(jié) Cronos 為 .NET 應(yīng)用程序提供了強(qiáng)大的定時(shí)任務(wù)調(diào)度能力。通過(guò)本文的控制臺(tái)示例,您可以輕松實(shí)現(xiàn)各種定時(shí)任務(wù)需求。記住要根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景選擇合適的 CRON 表達(dá)式,并始終關(guān)注任務(wù)的可靠性和性能。
該文章在 2024/12/25 10:15:10 編輯過(guò)