lez*_*lon 5 c# background-service async-await asp.net-core ihostedservice
在 ASP.NET Core 上,我观察到一种奇怪的行为,这实际上是在BackgroundService 中报告的,未关闭,stoppingToken 从未使用 .net core 通用主机设置,但从未找到根本原因
我正在创建以下BackgroundService任务,注册为HostedService:
唯一的方法是这样实现的:
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested )
Console.WriteLine("running");
}
Run Code Online (Sandbox Code Playgroud)
如果我尝试Ctrl+C或杀死-15这个,它不会停止。
如果我像这样更改函数:
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested )
{
Console.WriteLine("running");
await Task.Delay(1);
}
}
Run Code Online (Sandbox Code Playgroud)
这是有效的:如果我尝试Ctrl+C该程序,则会设置取消令牌,然后退出。
如果我返回到不起作用的版本并暂停它,我会看到即使我处于 ExecuteAsync 方法中,它下面的框架也是 StartAsync(),在这种情况下它永远不会完成!
我看到的 StartAsync() 代码(来自框架)是这样的:
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;
}
Run Code Online (Sandbox Code Playgroud)
那么,这是怎么回事?
我有两个问题:
为什么 ExecuteAsync 不在线程池上的另一个线程中从一开始就运行?我假设对的调用_executingTask = ExecuteAsync(_stoppingCts.Token);会立即返回,但显然情况并非如此,它正在等待第一个等待执行之后的行
我的代码不BackgroundService正确吗?据我所知,在异步函数中使用纯阻塞代码是合法的用例,它不应该导致整个应用程序永远阻塞
文档中几乎涵盖了这一点:
ExecuteAsync(CancellationToken)被调用来运行后台服务。该实现返回System.Threading.Tasks.Task代表后台服务的整个生命周期的 。ExecuteAsync在变为异步之前(例如通过调用),不会启动更多服务await。避免在ExecuteAsync.
await Task.Yield()简单的修复方法是在 的开始处调用ExecuteAsync:
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
await Task.Yield();
// ... rest of the code
}
Run Code Online (Sandbox Code Playgroud)
请注意,您的初始实现应该产生一条警告,抱怨缺少,await这暗示您可能正在做一些不完全正确的事情。