停止子系统:单个 CancellationToken 与 Stop 方法
Stopping subsystems: single CancellationToken vs Stop method
我有一个简单的 .net 核心控制台应用程序,其中包含几个长 运行 后台服务。服务在应用程序启动时启动。我想根据用户请求正确停止它们。 Microsoft 提供了基础 class 用于实现长 运行 - 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);
}
}
两种方法都解决了我的问题。但是在代码组织和匹配class语义方法方面我无法决定哪一个更好。您会选择哪种方法,为什么?
经过几年的发展,我准备好回答我自己的问题了。希望这会对其他人有所帮助。
如果您需要在应用程序的整个生命周期中处理某些东西,您应该选择后台服务(例如看门狗、评级更新程序、后台 email/SMS 发件人)。
如果你只是需要运行任何一种long-运行ning,但是限时操作,你应该选择Task.Factory.StartNew
和long-运行宁选项。
在大多数情况下,当您创建 .NET Core
应用程序时,后台服务适合您的大多数情况,因为在网络应用程序或后台工作人员中通常不需要 运行ning long-运行从您的代码中手动执行任务。
我有一个简单的 .net 核心控制台应用程序,其中包含几个长 运行 后台服务。服务在应用程序启动时启动。我想根据用户请求正确停止它们。 Microsoft 提供了基础 class 用于实现长 运行 - 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);
}
}
两种方法都解决了我的问题。但是在代码组织和匹配class语义方法方面我无法决定哪一个更好。您会选择哪种方法,为什么?
经过几年的发展,我准备好回答我自己的问题了。希望这会对其他人有所帮助。
如果您需要在应用程序的整个生命周期中处理某些东西,您应该选择后台服务(例如看门狗、评级更新程序、后台 email/SMS 发件人)。
如果你只是需要运行任何一种long-运行ning,但是限时操作,你应该选择Task.Factory.StartNew
和long-运行宁选项。
在大多数情况下,当您创建 .NET Core
应用程序时,后台服务适合您的大多数情况,因为在网络应用程序或后台工作人员中通常不需要 运行ning long-运行从您的代码中手动执行任务。