C#定时任务实现


引言

定时任务是软件开发中常见的需求,无论是数据备份、报表生成、系统监控还是消息推送,都需要可靠的定时执行机制。C#提供了多种实现定时任务的方式,从简单的Timer类到强大的调度框架,开发者可以根据项目需求选择最适合的方案。本文将全面介绍C#中实现定时任务的各种方法及其适用场景。

1. 基础定时器实现

1.1 System.Timers.Timer

System.Timers.Timer是.NET中最常用的定时器之一,适合服务端应用:

using System.Timers;

// 创建定时器(间隔毫秒)
var timer = new System.Timers.Timer(1000); 

// 设置自动重置(默认true)
timer.AutoReset = true;

// 绑定Elapsed事件
timer.Elapsed += (sender, e) => 
{
    Console.WriteLine($"定时任务执行时间: {e.SignalTime}");
};

// 开始计时
timer.Start();

// 停止计时
// timer.Stop();

// 记得在不再需要时释放资源
// timer.Dispose();

特点

  • 基于线程池工作
  • 精度较高(约10-20ms)
  • 适合服务端应用
  • 需要手动处理线程安全

1.2 System.Threading.Timer

更轻量级的定时器实现:

using System.Threading;

// 创建定时器(回调函数,状态对象,首次延迟,间隔)
var timer = new Timer(state => 
{
    Console.WriteLine($"任务执行时间: {DateTime.Now}");
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(1));

// 停止计时
// timer.Change(Timeout.Infinite, Timeout.Infinite);
// timer.Dispose();

特点

  • 最轻量级的定时器
  • 回调在线程池线程执行
  • 需要手动处理线程安全
  • 没有设计时支持

1.3 System.Windows.Forms.Timer

适用于Windows窗体应用程序:

using System.Windows.Forms;

var timer = new Timer();
timer.Interval = 1000; // 1秒
timer.Tick += (sender, e) =>
{
    Console.WriteLine($"窗体定时任务: {DateTime.Now}");
};
timer.Start();

特点

  • 在UI线程执行回调
  • 简单易用
  • 仅适用于WinForms应用
  • 精度较低(约55ms)

2. 高级定时任务框架

2.1 Hangfire – 专业作业调度系统

安装

Install-Package Hangfire

基本使用

// 配置
GlobalConfiguration.Configuration
    .UseSqlServerStorage("ConnectionString");

// 启动服务器
using (new BackgroundJobServer())
{
    // 简单任务
    BackgroundJob.Enqueue(() => Console.WriteLine("立即执行的任务"));

    // 延迟任务
    BackgroundJob.Schedule(
        () => Console.WriteLine("5分钟后执行"),
        TimeSpan.FromMinutes(5));

    // 循环任务
    RecurringJob.AddOrUpdate(
        "my-recurring-job",
        () => Console.WriteLine("每分钟执行"),
        Cron.Minutely);

    Console.ReadLine();
}

特点

  • 支持持久化存储
  • 分布式支持
  • 任务失败自动重试
  • 提供仪表板监控
  • 支持复杂调度规则

2.2 Quartz.NET – 企业级调度库

安装

Install-Package Quartz

基本使用

// 创建调度器工厂
var factory = new StdSchedulerFactory();
var scheduler = await factory.GetScheduler();
await scheduler.Start();

// 定义任务
var job = JobBuilder.Create<MyJob>()
    .WithIdentity("myJob", "group1")
    .Build();

// 定义触发器
var trigger = TriggerBuilder.Create()
    .WithIdentity("myTrigger", "group1")
    .StartNow()
    .WithSimpleSchedule(x => x
        .WithIntervalInSeconds(10)
        .RepeatForever())
    .Build();

// 调度任务
await scheduler.ScheduleJob(job, trigger);

任务类实现

public class MyJob : IJob
{
    public async Task Execute(IJobExecutionContext context)
    {
        await Console.Out.WriteLineAsync($"任务执行: {DateTime.Now}");
    }
}

特点

  • 企业级功能
  • 支持复杂调度表达式
  • 集群支持
  • 任务持久化
  • 事务支持

3. .NET Core/5+中的定时任务

3.1 BackgroundService + Timer

public class TimedBackgroundService : BackgroundService
{
    private readonly ILogger<TimedBackgroundService> _logger;
    private Timer _timer;

    public TimedBackgroundService(ILogger<TimedBackgroundService> logger)
    {
        _logger = logger;
    }

    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _timer = new Timer(DoWork, null, TimeSpan.Zero, 
            TimeSpan.FromSeconds(5));

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation($"后台任务执行: {DateTime.Now}");
    }

    public override void Dispose()
    {
        _timer?.Dispose();
        base.Dispose();
    }
}

3.2 IHostedService实现

public class TimedHostedService : IHostedService, IDisposable
{
    private readonly ILogger<TimedHostedService> _logger;
    private Timer _timer;

    public TimedHostedService(ILogger<TimedHostedService> logger)
    {
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("定时服务启动");
        _timer = new Timer(DoWork, null, TimeSpan.Zero, 
            TimeSpan.FromSeconds(5));
        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation($"定时任务执行: {DateTime.Now}");
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("定时服务停止");
        _timer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}

4. 定时任务最佳实践

4.1 错误处理

private void DoWork(object state)
{
    try
    {
        // 业务逻辑
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "定时任务执行失败");
        // 根据需求决定是否继续
    }
}

4.2 避免任务重叠

private int _isRunning = 0;

private void DoWork(object state)
{
    if (Interlocked.CompareExchange(ref _isRunning, 1, 0) != 0)
    {
        _logger.LogWarning("前一个任务仍在执行,跳过本次执行");
        return;
    }

    try
    {
        // 业务逻辑
    }
    finally
    {
        Interlocked.Exchange(ref _isRunning, 0);
    }
}

4.3 动态调整间隔

private Timer _timer;

private void InitializeTimer()
{
    _timer = new Timer(DoWork, null, TimeSpan.Zero, 
        GetNextInterval());
}

private TimeSpan GetNextInterval()
{
    // 根据业务逻辑计算下次执行间隔
    return TimeSpan.FromMinutes(30);
}

private void DoWork(object state)
{
    try
    {
        // 业务逻辑
    }
    finally
    {
        // 动态调整间隔
        _timer.Change(GetNextInterval(), Timeout.InfiniteTimeSpan);
    }
}

4.4 资源清理

public void Dispose()
{
    _timer?.Dispose();
    // 清理其他资源
}

5. 定时任务设计模式

5.1 策略模式实现不同任务

public interface ITaskStrategy
{
    Task ExecuteAsync();
}

public class DataSyncTask : ITaskStrategy
{
    public async Task ExecuteAsync()
    {
        // 数据同步逻辑
    }
}

public class ReportGenerationTask : ITaskStrategy
{
    public async Task ExecuteAsync()
    {
        // 报表生成逻辑
    }
}

// 在定时器中使用
private async void DoWork(object state)
{
    ITaskStrategy task = GetCurrentTask(); // 根据条件获取具体策略
    await task.ExecuteAsync();
}

5.2 装饰器模式添加功能

public abstract class TaskDecorator : ITaskStrategy
{
    private readonly ITaskStrategy _inner;

    protected TaskDecorator(ITaskStrategy inner)
    {
        _inner = inner;
    }

    public virtual async Task ExecuteAsync()
    {
        await _inner.ExecuteAsync();
    }
}

public class LoggingDecorator : TaskDecorator
{
    private readonly ILogger _logger;

    public LoggingDecorator(ITaskStrategy inner, ILogger logger) 
        : base(inner)
    {
        _logger = logger;
    }

    public override async Task ExecuteAsync()
    {
        _logger.LogInformation("任务开始执行");
        try
        {
            await base.ExecuteAsync();
            _logger.LogInformation("任务执行成功");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "任务执行失败");
            throw;
        }
    }
}

结语

C#提供了从简单到复杂的多种定时任务实现方案,开发者应根据项目需求选择合适的方法。对于简单需求,System.Timers.TimerSystem.Threading.Timer已足够;对于复杂的企业级应用,Hangfire或Quartz.NET提供了更强大的功能;而在.NET Core/5+应用中,BackgroundServiceIHostedService提供了与现代框架深度集成的解决方案。

无论选择哪种方式,都应注意错误处理、资源管理和任务隔离,确保定时任务的稳定性和可靠性。通过合理的设计模式和最佳实践,可以构建出既灵活又健壮的定时任务系统。


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注