Lar*_*rry 2 c# task background-service asp.net-core
我在 aspnet 核心应用程序中使用BackgroundService对象。
关于 ExecuteAsync 方法中运行的操作的实现方式,Aspnet 核心无法正确初始化或停止。这是我尝试过的:
我按照文档ExecuteAsync中解释的方式实现了抽象方法。
管道变量是IEnumerable<IPipeline>注入到构造函数中的变量。
public interface IPipeline {
Task Start();
Task Cycle();
Task Stop();
}
...
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
log.LogInformation($"Starting subsystems");
foreach(var engine in pipeLine) {
try {
await engine.Start();
}
catch(Exception ex) {
log.LogError(ex, $"{nameof(engine)} failed to start");
}
}
log.LogInformation($"Runnning main loop");
while(!stoppingToken.IsCancellationRequested) {
foreach(var engine in pipeLine) {
try {
await engine.Cycle();
}
catch(Exception ex) {
log.LogError(ex, $"{engine.GetType().Name} error in Cycle");
}
}
}
log.LogInformation($"Stopping subsystems");
foreach(var engine in pipeLine) {
try {
await engine.Stop();
}
catch(Exception ex) {
log.LogError(ex, $"{nameof(engine)} failed to stop");
}
}
}
Run Code Online (Sandbox Code Playgroud)
由于项目当前的开发状态,有许多“nop”Pipeline 包含这样实现的空 Cycle() 操作:
public async Task Cycle() {
await Task.CompletedTask;
}
Run Code Online (Sandbox Code Playgroud)
我注意到的是:
如果至少一个IPipeline 对象包含实际的异步方法(await Task.Delay(1)),那么一切都会顺利运行,我可以使用 CTRL+C 优雅地停止服务。
如果所有IPipeline 对象都包含 wait Task.CompletedTask;,
那么一方面,aspnetcore无法正确初始化。我的意思是,没有“正在侦听:http://[::]:10001应用程序已启动。按 Ctrl+C 关闭。” 在控制台上。
另一方面,当我按下 CTRL+C 时,控制台显示“应用程序正在关闭...”,但循环继续运行,就好像 CancellationToken 从未被请求停止一样。
基本上,如果我将单个 Pipeline 对象更改为:
public async Task Cycle() {
await Task.Delay(1);
}
Run Code Online (Sandbox Code Playgroud)
然后一切都很好,我不明白为什么。有人可以向我解释一下我对任务处理不理解的地方吗?
最简单的解决方法是将其添加await Task.Yield();为第一行ExecuteAsync。
我不是专家......但“问题”是其中的所有代码ExecuteAsync实际上都是同步运行的。
如果所有“周期”返回一个已同步完成的任务(如 Task.CompletedTask 所示),则该while方法ExecuteAsync永远不会“yield”。
IHostedService该框架本质上是对注册的s 和调用执行 foreach StartAsync。如果你的服务没有屈服,那么 foreach 就会被阻塞。因此任何其他服务(包括 AspNetCore 主机)都不会启动。由于引导无法完成,因此 ctrl-C 处理等也永远无法设置。
放入await Task.Delay(1)其中一个周期“释放”或“产生”任务。这允许主机“捕获”任务并继续。这允许取消等的连接发生。
放在Task.Yield()顶部ExecuteAsync只是实现此目的的更直接方法,并且意味着周期根本不需要意识到这个“问题”。
注意:这通常只是测试中的一个真正问题......为什么你会有一个无操作周期?
注意2:如果您可能有“计算”周期(即它们不执行任何IO、数据库、队列等),那么切换到ValueTask 将有助于性能/分配。
| 归档时间: |
|
| 查看次数: |
1979 次 |
| 最近记录: |