点网核心3.0工人服务模板如下所示:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
});
}
“ Worker”类派生自BackgroundService。每隔1000毫秒就会循环将日志写入控制台。
我的问题:
我可以同时运行多个“工人”吗? (我知道我可以创建另一个类“ Worker2”。但是我可以运行同一类“ Worker”的两个副本吗?)
如果是,如何配置具有不同配置或参数的两个“ Worker”,例如,两个具有不同循环间隔的Worker? (因为“ Worker”类的实例是由DI框架创建的。我不知道如何将不同的配置/参数传递给“ Worker”的两个不同实例)
答案 0 :(得分:10)
您可以有一个“父母”工人像这样启动“真正”工人...
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var workers = new List<Task>();
foreach(var delay in _config.LoopIntervals)
workers.Add(DoRealWork(delay, stoppingToken));
await Task.WhenAll(workers.ToArray());
}
}
然后...
private async Task DoRealWork(int delay, CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("worker {delay} checking in at {time}", delay, DateTimeOffset.Now);
await Task.Delay(delay, stoppingToken);
}
}
_config从appSettings.json填充并像这样传递给Worker的构造函数...
var cfg = hostContext.Configuration.GetSection(nameof(WorkerConfig)).Get<WorkerConfig>();
services.AddSingleton(cfg);
services.AddHostedService<Worker>();
和appSettings ...
{
"WorkerConfig": {
"LoopIntervals": [ 1000, 2000, 3000 ]
}
}
答案 1 :(得分:0)
“ AddHostedService”不接受两次注册的同一类的原因:
我检查了“ AddHostedService”的github源,发现它的实现方式如下:
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, THostedService>());
根据Microsoft的“ TryAddEnumerable”方法文档,仅当集合不包含相同服务和实现类型的其他注册时,才添加服务。这就是为什么我不能运行“ Worker”的两个副本的原因。 (“ TryAddEnumerable”用于避免为同一服务创建多个实例。参考:https://github.com/aspnet/Extensions/issues/1078)
解决方案:
所以我可以直接使用“ AddSingleton”添加两个工作程序...
services.AddSingleton<IHostedService, Worker>();
services.AddSingleton<IHostedService, Worker>();
有效。
将参数传递给服务构造函数:
然后,我通过为循环间隔添加第二个参数来修改Worker类的构造函数。最后,我使用实现工厂注册服务,如下所示
services.AddSingleton<IHostedService>(sp => new Worker(sp.GetService<ILogger<Worker>>(), 1000));
services.AddSingleton<IHostedService>(sp => new Worker(sp.GetService<ILogger<Worker>>(), 2000));