【问题标题】:Stopping subsystems: single CancellationToken vs Stop method停止子系统:单个 CancellationToken vs Stop 方法
【发布时间】:2019-03-09 15:18:02
【问题描述】:

我有一个简单的 .net 核心控制台应用程序,其中包含几个长时间运行的后台服务。服务在应用程序启动时启动。我想根据用户请求正确停止它们。微软提供了实现长期运行的基类——BackgroundService

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

    /// <summary>
    /// This method is called when the <see cref="T:Microsoft.Extensions.Hosting.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="M:Microsoft.Extensions.Hosting.IHostedService.StopAsync(System.Threading.CancellationToken)" /> is called.</param>
    /// <returns>A <see cref="T:System.Threading.Tasks.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)
    {
      this._executingTask = this.ExecuteAsync(this._stoppingCts.Token);
      if (this._executingTask.IsCompleted)
        return this._executingTask;
      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)
    {
      if (this._executingTask == null)
        return;
      try
      {
        this._stoppingCts.Cancel();
      }
      finally
      {
        Task task = await Task.WhenAny(this._executingTask, Task.Delay(-1, cancellationToken));
      }
    }

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

BackgroundService 允许通过调用方法StopAsync 停止服务。 我们也可以通过这种方式实现长时间运行的服务,使用单一方法和取消令牌:

public class LongRunningService
{
    public Task RunAsync(CancellationToken token)
    {
        return Task.Factory.StartNew(() =>
            {
                // here goes something long running
                while (!token.IsCancellationRequested)
                {

                }
            },
            TaskCreationOptions.LongRunning);
    }
}

这两种方法都解决了我的问题。但是在代码组织和匹配类语义方法方面,我无法确定哪一个更好。你会选择什么方法,为什么?

【问题讨论】:

    标签: .net architecture .net-core task-parallel-library


    【解决方案1】:

    经过几年的发展,我已经准备好回答我自己的问题了。希望这对其他人有帮助。

    如果您需要在应用程序的整个生命周期中处理某些内容,您应该选择后台服务(例如看门狗、评级更新程序、后台电子邮件/短信发送者)。

    如果你只需要运行任何一种长时间运行,但有时间限制的操作,你应该选择Task.Factory.StartNew with long-running options。

    在大多数情况下,当您创建 .NET Core 应用程序时,后台服务适合您的大多数情况,因为在 Web 应用程序或后台工作人员中,通常不需要手动从您的代码中运行长时间运行的任务。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-18
      • 1970-01-01
      • 1970-01-01
      • 2017-12-20
      • 2019-04-28
      • 2020-08-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多