.net core BackgroundService
or IHostedService
's start method is async:
//IHostedService
Task StartAsync(CancellationToken cancellationToken);
//BackgroundService
Task ExecuteAsync(CancellationToken stoppingToken);
So should I write all the logic in the ExecuteAsync
/StartAsync
method, or should I just start a new thread and return right away?
For example, which of the following two is the correct implementation?
1.
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
new Thread(async () => await DoWork(stoppingToken)).Start();
await Task.CompletedTask;
}
private async Task DoWork(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
//actual works
}
2.
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
//actual works
await Task.Delay(1000);//e.g
}
}
Semantically I think the second one seems to be right, but if there're several IHostedService
s, can they run in parallel with the second form?
Edit 1
I also write a sample program that illustrate the hosted services aren't themselves run as seperated threads.
The message "Waiting for signal.."
won't be written console until I type a q
:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace BackgroundTaskTest
{
public class Program
{
public static async Task Main(string[] args)
{
var host = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
IConfiguration config = hostContext.Configuration;
//register tasks
services.AddHostedService<ReadService>();
services.AddHostedService<BlockService>();
})
.UseConsoleLifetime()
.Build();
await host.RunAsync();
}
}
public static class WaitClass
{
public static AutoResetEvent Event = new AutoResetEvent(false);
}
public class ReadService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var c = Console.ReadKey();
if (c.KeyChar == 'q')
{
Console.WriteLine("\nTrigger event");
WaitClass.Event.Set();
}
await Task.Delay(1);
}
}
}
public class BlockService : BackgroundService
{
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
Console.WriteLine("Waiting for signal..");
WaitClass.Event.WaitOne();
Console.WriteLine("Signal waited");
}
return Task.CompletedTask;
}
}
}
await
operation is reached. And that is the behaviour ofasync
operations that it may put those async operations to seperated threads, ,but I think it is not guaranteed thatawait
will put the operation to a seperated thread... – Modelawait
is continuation, and they may or may not run in another thread from the origin. From my test code, all host services run in the same thread (because former one will block later ones), and only with aawait Task.Delay(xxx)
will the following services be running. After the delay times out, the former services could run in parallel with the later ones because former services are continuation and may run in seperated threads. But as you mentioned, it's not guaranteed, so I still need to create thread myself .... – Model