<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          .NET Core 實(shí)現(xiàn)定時任務(wù) BackgroundService

          共 8158字,需瀏覽 17分鐘

           ·

          2022-07-22 13:52


          前言


          在上一篇文檔中說到使用 IHostedService 接口實(shí)現(xiàn)定時任務(wù)傳送門:https://www.cnblogs.com/ysmc/p/16456787.html,其中,有小伙伴就問到,為什么不使用 BackgroundService,我個人覺得使用什么技術(shù),應(yīng)該取決于需求,代碼只是一種工具,用得順手對于編碼人員來說,我個人感覺還是非常重要的;正好也說到了 BackgroundService,那這一篇文檔就簡單說一下它吧。


          正文

          首先我們看一下官方的說明,學(xué)習(xí)代碼一定要看官方的文檔,盡管有時候會有點(diǎn)晦澀難懂,但肯定是最正確的:

          BackgroundService 基

          BackgroundService 是用于實(shí)現(xiàn)長時間運(yùn)行的 IHostedService 的基類。

          調(diào)用 ExecuteAsync(CancellationToken) 來運(yùn)行后臺服務(wù)。實(shí)現(xiàn)返回一個 Task,其表示后臺服務(wù)的整個生存期。

          在 ExecuteAsync 變?yōu)楫惒剑ɡ缤ㄟ^調(diào)用 await)之前,不會啟動任何其他服務(wù)。避免在 ExecuteAsync 中執(zhí)行長時間的阻塞初始化工作。

          StopAsync(CancellationToken) 中的主機(jī)塊等待完成 ExecuteAsync

          調(diào)用 IHostedService.StopAsync 時,將觸發(fā)取消令牌。當(dāng)激發(fā)取消令牌以便正常關(guān)閉服務(wù)時,ExecuteAsync 的實(shí)現(xiàn)應(yīng)立即完成。否則,服務(wù)將在關(guān)閉超時后不正常關(guān)閉。

          StartAsync 應(yīng)僅限于短期任務(wù),因?yàn)橥泄芊?wù)是按順序運(yùn)行的,在 StartAsync 運(yùn)行完成之前不會啟動其他服務(wù)。長期任務(wù)應(yīng)放置在 ExecuteAsync 中。

          針對第一點(diǎn)“BackgroundService 是用于實(shí)現(xiàn)長時間運(yùn)行的 IHostedService 的基類”,我們先看看 BackgroundService 的源碼:

          public abstract class BackgroundService : IHostedServiceIDisposable
          {
              private Task _executingTask;
              private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();

              /// <summary>
              /// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
              /// the lifetime of the long running operation(s) being performed.
              /// /// </summary>
              /// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param>
              /// <returns><see cref="Task"/> that represents the long running operations.</returns>
              protected abstract Task ExecuteAsync(CancellationToken stoppingToken);

              /// <summary>
              /// Triggered when the application host is ready to start the service.
              /// </summary>
              /// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
              public virtual Task StartAsync(CancellationToken cancellationToken)
              {
                  // Store the task we're executing
                  _executingTask = ExecuteAsync(_stoppingCts.Token);

                  // If the task is completed then return it, this will bubble cancellation and failure to the caller
                  if (_executingTask.IsCompleted)
                  {
                      return _executingTask;
                  }

                  // Otherwise it's running
                  return Task.CompletedTask;
              }

              /// <summary>
              /// Triggered when the application host is performing a graceful shutdown.
              /// </summary>
              /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
              public virtual async Task StopAsync(CancellationToken cancellationToken)
              {
                  // Stop called without start
                  if (_executingTask == null)
                  {
                      return;
                  }

                  try
                  {
                      // Signal cancellation to the executing method
                      _stoppingCts.Cancel();
                  }
                  finally
                  {
                      // Wait until the task completes or the stop token triggers
                      await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
                  }

              }

              public virtual void Dispose()
              {
                  _stoppingCts.Cancel();
              }
          }

          以上代碼很好的解答了小伙伴提出“為什么不使用 BackgroundService”的問題,在上一篇文章中,評論區(qū)的一位大佬也很好的回答了這位小伙伴的問題,我這里引用下這位大佬的原話:“BackgroundService 是 IHostedService的一個簡單實(shí)現(xiàn),內(nèi)部IHostedService 的StartAsync調(diào)用了ExecuteAsync”,本質(zhì)上就是使用了 IHostedService;

          讓我們回到正題,怎么用 BackgroundService 實(shí)現(xiàn)定時任務(wù)呢,老規(guī)矩,上代碼:

          首先,創(chuàng)建一個服務(wù)接口,定義需要實(shí)現(xiàn)的任務(wù),以及對應(yīng)的實(shí)現(xiàn),如果需要執(zhí)行異步方法,記得加上 await,不然任務(wù)將不會等待執(zhí)行結(jié)果,直接進(jìn)行下一個任務(wù)。

          public class TaskWorkService : ITaskWorkService
          {
              public async Task TaskWorkAsync(CancellationToken stoppingToken)
              {
                  while (!stoppingToken.IsCancellationRequested)
                  {
                      //執(zhí)行任務(wù)
                      Console.WriteLine($"{DateTime.Now}");

                      //周期性任務(wù),于上次任務(wù)執(zhí)行完成后,等待5秒,執(zhí)行下一次任務(wù)
                      await Task.Delay(500);
                  }
              }
          }

          注冊服務(wù)

          builder.Services.AddScoped<ITaskWorkService, TaskWorkService>();

          創(chuàng)建后臺服務(wù)類,繼承基類 BackgroundService,這里需要注意的是,要在 BackgroundService 中使用有作用域的服務(wù),請創(chuàng)建作用域, 默認(rèn)情況下,不會為托管服務(wù)創(chuàng)建作用域,得自己管理服務(wù)的生命周期,切記!于構(gòu)造函數(shù)中注入 IServiceProvider即可。

          public class BackgroundServiceDemo : BackgroundService
          {
              private readonly IServiceProvider _services;

              public BackgroundServiceDemo(IServiceProvider services)
              {
                  _services = services;
              }

              protected override async Task ExecuteAsync(CancellationToken stoppingToken)
              {
                  using var scope = _services.CreateScope();

                  var taskWorkService = scope.ServiceProvider.GetRequiredService<ITaskWorkService>();

                  await taskWorkService.TaskWorkAsync(stoppingToken);
              }
          }

          最后別忘了這個類也是需要注冊的,注冊方式與 IHostedService 接口的方式一樣

          builder.Services.AddHostedService<BackgroundServiceDemo>();

          大功告成,F(xiàn)5看看效果吧

          最后

          Bootstrap Blazor官網(wǎng)地址:https://www.blazor.zone,希望大佬們看到這篇文章,能給項(xiàng)目點(diǎn)個star支持下,感謝各位!

          轉(zhuǎn)自:一事冇誠

          鏈接:cnblogs.com/ysmc/p/16468560.html

          瀏覽 128
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  www.玖玖在线 | 欧美黑人性爱 | 中文字幕成人免费视频 | AExXxX国产 | 久热精品免费 |