C# 如何在.net core的后台服务中以不同的计时器持续时间运行多个任务

C# 如何在.net core的后台服务中以不同的计时器持续时间运行多个任务,c#,.net-core,asp.net-core-hosted-services,C#,.net Core,Asp.net Core Hosted Services,我正在创建一个将作为windows服务运行的辅助服务。我需要调用两个可能有不同计时器的任务 Saydoork应该每5分钟调用一次,而DoAnotherWork应该每10分钟左右调用一次。这两个任务可以并行运行,并且互不依赖 我能够创建taskDoWork,每5分钟运行一次。对于如何实现另一个具有不同计时器持续时间的任务,我有点困惑 public class Worker : BackgroundService { private readonly IServiceScop

我正在创建一个将作为windows服务运行的辅助服务。我需要调用两个可能有不同计时器的任务

Say
doork
应该每5分钟调用一次,而
DoAnotherWork
应该每10分钟左右调用一次。这两个任务可以并行运行,并且互不依赖

我能够创建task
DoWork
,每5分钟运行一次。对于如何实现另一个具有不同计时器持续时间的任务,我有点困惑

public class Worker : BackgroundService
{        
    private readonly IServiceScopeFactory _scopeFactory;        
    private IDataLoaderService _dataLoaderService;        

    public override Task StartAsync(CancellationToken cancellationToken)
    {
        using var scope = _scopeFactory.CreateScope();
        _dataLoaderService = scope.ServiceProvider.GetRequiredService<IDataLoaderService>();                        
        return base.StartAsync(cancellationToken);
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {            
        while (!stoppingToken.IsCancellationRequested)
        {
            await DoWork(stoppingToken, _dataLoaderService);
            await Task.Delay(300000, stoppingToken); //Run every 5 minutes

            await DoAnotherWork(stoppingToken, _dataLoaderService);
            await Task.Delay(600000, stoppingToken); //Run every 10 minutes
        }
    }

    private async Task DoWork(CancellationToken stoppingToken, IDataLoaderService loaderService)
    {
        await loaderService.Process();            
    }        
    
    private async Task DoAnotherWork(CancellationToken stoppingToken, IDataLoaderService loaderService)
    {
        await loaderService.Validate();            
    }
}
public class Worker:BackgroundService
{        
专用读写器ViceScopeFactory\u scopeFactory;
专用IDataLoaderService(数据加载服务);;
公共覆盖任务StartAsync(CancellationToken CancellationToken)
{
使用var scope=_scopeFactory.CreateScope();
_dataLoaderService=scope.ServiceProvider.GetRequiredService();
返回base.StartAsync(cancellationToken);
}
受保护的覆盖异步任务ExecuteAsync(CancellationToken stoppingToken)
{            
同时(!stoppingToken.IsCancellationRequested)
{
等待工作(停止停止,数据加载服务);
等待任务。延迟(300000,停止);//每5分钟运行一次
等待完成其他工作(停止通话,数据加载服务);
等待任务。延迟(600000,停止);//每10分钟运行一次
}
}
专用异步任务DoWork(CancellationToken stoppingToken,IDataLoaderService loaderService)
{
等待loaderService.Process();
}        
专用异步任务DoAnotherWork(取消令牌停止工作,IDataLoaderService loaderService)
{
等待loaderService.Validate();
}
}

如果您不想在您的案例中使用现有的调度库,您可以使用两个计时器,就像在这里一样,其中使用了
System.Threading.Timer
。诸如此类:

public class Worker : IHostedService, IDisposable
{        
    private readonly IServiceScopeFactory _scopeFactory;        
    private IDataLoaderService _dataLoaderService;  
    private Timer _timer1;
    private Timer _timer2;      

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _dataLoaderService = scope.ServiceProvider.GetRequiredService<IDataLoaderService>();              
        _timer1 = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(300));
        _timer2 = new Timer(DoAnotherWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(600));
        return Task.CompletedTask;
    }    
   
    private async void DoWork(object _)
    {
        // or create scope and resolve here
        await _loaderService.Process();            
    }        
    
    private async void DoAnotherWork(object _)
    {
        // or create scope and resolve here
        await _loaderService.Validate();            
    }

    public Task StopAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Timed Hosted Service is stopping.");

        _timer1?.Change(Timeout.Infinite, 0);
        _timer2?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer1?.Dispose();
        _timer2?.Dispose();
    }
}
公共类工作者:IHostedService,IDisposable
{        
专用读写器ViceScopeFactory\u scopeFactory;
专用IDataLoaderService(数据加载服务);;
专用定时器_timer1;
专用定时器_timer2;
公共任务StartSync(CancellationToken CancellationToken)
{
_dataLoaderService=scope.ServiceProvider.GetRequiredService();
_timer1=新计时器(DoWork,null,TimeSpan.Zero,TimeSpan.FromSeconds(300));
_timer2=新计时器(DoAnotherWork,null,TimeSpan.Zero,TimeSpan.FromSeconds(600));
返回Task.CompletedTask;
}    
专用异步void DoWork(对象)
{
//或者在此处创建范围并解析
wait_loaderService.Process();
}        
私有异步void DoAnotherWork(对象)
{
//或者在此处创建范围并解析
wait_loaderService.Validate();
}
公共任务StopAsync(CancellationToken stoppingToken)
{
_logger.LogInformation(“定时托管服务正在停止”);
_timer1?.Change(Timeout.Infinite,0);
_timer2?更改(Timeout.Infinite,0);
返回Task.CompletedTask;
}
公共空间处置()
{
_timer1?.Dispose();
_timer2?.Dispose();
}
}
这两个任务可以并行运行,并且互不依赖

听起来你有两项服务:

public class ProcessDataLoaderWorker : BackgroundService
{
  private readonly IServiceScopeFactory _scopeFactory;

  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    using var scope = _scopeFactory.CreateScope();
    var dataLoaderService = scope.ServiceProvider.GetRequiredService<IDataLoaderService>();

    while (true)
    {
      await dataLoaderService.Process();
      await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken); //Run every 5 minutes
    }
  }
}

public class ValidateDataLoaderWorker : BackgroundService
{
  private readonly IServiceScopeFactory _scopeFactory;

  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    using var scope = _scopeFactory.CreateScope();
    var dataLoaderService = scope.ServiceProvider.GetRequiredService<IDataLoaderService>();

    while (true)
    {
      await dataLoaderService.Validate();
      await Task.Delay(TimeSpan.FromMinutes(10), stoppingToken); //Run every 10 minutes
    }
  }
}
公共类ProcessDataLoaderWorker:BackgroundService
{
专用读写器ViceScopeFactory\u scopeFactory;
受保护的覆盖异步任务ExecuteAsync(CancellationToken stoppingToken)
{
使用var scope=_scopeFactory.CreateScope();
var dataLoaderService=scope.ServiceProvider.GetRequiredService();
while(true)
{
等待dataLoaderService.Process();
等待任务。延迟(TimeSpan.FromMinutes(5),stoppingToken);//每5分钟运行一次
}
}
}
公共类ValidateDataLoaderWorker:后台服务
{
专用读写器ViceScopeFactory\u scopeFactory;
受保护的覆盖异步任务ExecuteAsync(CancellationToken stoppingToken)
{
使用var scope=_scopeFactory.CreateScope();
var dataLoaderService=scope.ServiceProvider.GetRequiredService();
while(true)
{
等待dataLoaderService.Validate();
等待任务。延迟(TimeSpan.FromMinutes(10),stoppingToken);//每10分钟运行一次
}
}
}

我还修改了
IDataLoaderService
的使用方式,使其不在其范围之外使用,并更改了
任务。延迟
参数,使其更易于解释。

如果您不想使用Hangfire或Quartz,可以使用其中一个计时器(例如)@GuruStron你能详细说明我如何在
ExecuteAsync
StartAsync
方法中使用
Timer
吗?使用
IHostedService
BackgroundService
有什么好处吗?@Shaggy你不需要考虑从哪里开始计时=)明白了。我试过你的代码,不知道为什么,但它只是立即执行
DoWork
不会每5分钟调用一次。
BackgroundService
现在更适用。@Pure.Krome为什么会这样?我会在循环之前添加一个
Wait Task.Yield()
,因为在第一次
wait
之前出现异常会导致启动失败。@Jeremylakman:I通常情况下。@StephenCleary这里有两个问题:1)这两个问题是如何“连接”起来的?2) 为什么在(!stoppingToken.IsCancellationRequested)时使用
while(true)
而不是
while(!stoppingToken.IsCancellationRequested)
。。如果要求取消。。。然后,这将优雅地结束这两个后台任务?@Pure.Krome:1)您可以使用
AddHostedService
添加多个服务。2) NET中的标准取消模式是抛出
OperationCanceledException
,因此我强烈避免
IsCancellationReq