1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 8158字,需瀏覽 17分鐘

         ·

        2022-07-22 13:52


        前言


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


        正文

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

        BackgroundService 基

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

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

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

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

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

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

        針對(duì)第一點(diǎn)“BackgroundService 是用于實(shí)現(xiàn)長(zhǎng)時(shí)間運(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”的問(wèn)題,在上一篇文章中,評(píng)論區(qū)的一位大佬也很好的回答了這位小伙伴的問(wèn)題,我這里引用下這位大佬的原話:“BackgroundService 是 IHostedService的一個(gè)簡(jiǎn)單實(shí)現(xiàn),內(nèi)部IHostedService 的StartAsync調(diào)用了ExecuteAsync”,本質(zhì)上就是使用了 IHostedService;

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

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

        注冊(cè)服務(wù)

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

        創(chuàng)建后臺(tái)服務(wù)類,繼承基類 BackgroundService,這里需要注意的是,要在 BackgroundService 中使用有作用域的服務(wù),請(qǐng)創(chuàng)建作用域, 默認(rèn)情況下,不會(huì)為托管服務(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);
            }
        }

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

        builder.Services.AddHostedService<BackgroundServiceDemo>();

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

        最后

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

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

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

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            草逼爽| а天堂中文官网 | 日产av在线免费观看 | 欧美成人精品无码 | 国产精品无码不卡 | 2攻一受做哭调教高h | 爱搞网站 | 偷拍精偷拍精品欧洲亚洲网站 | 掀开白丝袜jk裙子扒掉内裤 | 极品人妻一区二区三区 |