下面是运行IHostedService
的简单代码
internal class Program {
public static Task Main(string[] args) {
var host = new HostBuilder().ConfigureServices((hostcontext, services) => {
services.AddHostedService<MyService>();
}).Build();
host.Run();
return Task.CompletedTask;
}
}
public class MyService : IHostedService {
public Task StartAsync(CancellationToken cancellationToken) {
return Task.Run(() => {
while (true) {
Console.WriteLine("Starting Service");
}
});
}
public Task StopAsync(CancellationToken cancellationToken) {
Console.WriteLine("Stopping service");
return Task.CompletedTask;
}
}
字符串
因此,当我想通过在控制台中按下Ctrl + C来停止服务时,我希望看到服务停止,控制台打印“正在停止服务”。
但是当我按下Ctrl + C时,服务继续在无限循环中运行,我不明白。
我认为Task.Run()
在线程池中排队一个工作项,然后从线程池中排队一个后台线程来拾取作业,因此在我的示例中,它是一个工作线程(工作线程的id是4,主线程的id是1),执行while循环。所以当我按下Ctrl + S时,服务应该停止,那么为什么运行的后台线程停止正在停止的服务,当一个应用程序终止时,所有的后台作业/线程也会终止吗?我的意思是,如果Task.Run()
运行时创建了一个前台线程,那么我可以理解,因为所有的前台线程都需要在应用程序停止之前完成。
附注:
我可以传递CancellationToken
来停止while循环,我知道我可以这样做,在while循环中,我检查令牌是否可以调用等等。
但是我不明白为什么我必须这样做,因为运行的线程是后台线程,而不是前台线程,所以为什么所有后台线程都需要首先完成StopAsync()
才能被调用?即一个运行的后台线程如何停止exection流到达StopAsync()
?
3条答案
按热度按时间pkln4tw61#
如果你想停止一个任务,尝试使用MyServiceClass中的取消令牌
下面是我的例子:
字符串
to94eoyn2#
Ctrl+C不会直接终止控制台应用程序的原因,就像你可能习惯于从“普通”控制台应用程序一样,是因为.NET实际上支持阻止Ctrl+C终止应用程序,并让应用程序对Ctrl+C做出React并“做些事情”。
您使用的宿主框架使用了这个系统,一个事件,以防止您的应用程序被强制终止以及接管关闭过程。
事件本身是
Console.CancelKeyPress
,这是一个 * 可取消的事件 *,意味着您可以从事件处理程序返回,并在EventArgs对象上设置一个标志,以向调用事件处理程序的代码发出信号,表明您希望退出Ctrl+C的默认处理。托管框架已经做到了这一点。
你可以在这里看到确切的代码:Microsoft. Extensions. Hosting/Internal/ConsoleLifetime.cs@48 -52:
字符串
除了取消正常的关闭过程之外,托管框架提供的事件处理程序还取消了传递给StartAsync的令牌CancellationToken。正如您所说,如果您将此令牌传递给任务并对其被取消做出React,则应用程序将关闭。
对
ApplicationLifetime.StopApplication
的调用最终在Microsoft. Extensions. Hosting/Internal/ApplicationLifetime.cs@102 -112中结束:型
这就是为什么你的应用程序总是在无限循环中旋转的原因,正是因为宿主框架阻止了普通的关闭,而是给予你的任务一个机会来有序地完成。因为你的任务忽略了这个请求,只是继续运行,所以当你按下Ctrl+C时,你的进程永远不会终止。
zmeyuzjn3#
不确定这是否涵盖了你想要实现的100%,但是不要实现
IHostedService
,尝试从BackgroundService
继承,然后重写StartAsync
,StopAsync
和ExecuteAsync
,如下所示:字符串
基本上,您将利用
BackgroundService
的start/stop实现,这与Mugurel在他的回答中尝试实现的类似,但Microsoft的实现实际上是有效的:)你也可以看看它们的实现,只是为了获得灵感。