Выносится ли в отдельный поток BackgroundService asp.net core
Уже долгое время не могу найти ответ на свой вопрос. Выносится ли в отдельный поток BackgroundService? Заходил на форумы, увидел ответ, что фоновая задача помечается как LongRunning, и каждому фоновому сервису выделяется отдельный поток, но при эксперименте
class TestService(ILogger<s> loger) : BackgroundService
{
private readonly ILogger<s> _loger = loger;
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
_loger.LogInformation("Фоновая задача запущена");
while (!stoppingToken.IsCancellationRequested)
{
_loger.LogInformation("Цикл");
}
}
}
все приложение зависает и не запускается
Но если добавить в первой строчке await Task.Yield()
, или другую строку, содержащая await с асинхронной операцией , то приложение благополучно запустится, а задача впоследствии продолжит выполняться. Что это значит. Фоновая задача не выполняется в отдельном потоке, а в главном? Или она выполняется в главном потоке до первого await
а после переносится в отдельный поток?
Ответы (1 шт):
Метод ExecuteAsync
вызывается в том же потоке, который обрабатывает StartAsync
. Это можно увидеть в коде BackgroundService.
public virtual Task StartAsync(CancellationToken cancellationToken)
{
// Create linked token to allow cancelling executing task from provided token
_stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
// Store the task we're executing
_executeTask = ExecuteAsync(_stoppingCts.Token);
// If the task is completed then return it, this will bubble cancellation and failure to the caller
if (_executeTask.IsCompleted)
{
return _executeTask;
}
// Otherwise it's running
return Task.CompletedTask;
}
Фоновость реализуется не за счет выделенного потока, а за счет механизма TAP (Task-based Asynchronous Pattern). StartAsync
не ждет завершения ExecuteAsync
. Вместо этого он ожидает, что ExecuteAsync
немедленно вернет Task
, а его выполнение продолжится в фоне. Если внутри ExecuteAsync
запустить бесконечный цикл без await
, то он навсегда блокирует поток, в котором был запущен. Бесконечные циклы внутри BackgroundService
должны быть асинхронными, чтобы не блокировать поток.