Должно ли ядро ​​.net `IHostedService` начать новый поток - PullRequest
0 голосов
/ 10 июня 2019

.net core BackgroundService или IHostedService метод запуска асинхронный:

//IHostedService
Task StartAsync(CancellationToken cancellationToken);
//BackgroundService
Task ExecuteAsync(CancellationToken stoppingToken);

Так что я должен написать всю логику в методе ExecuteAsync / StartAsync, или я долженпросто начать новый поток и сразу же вернуться?

Например, какая из следующих двух является правильной реализацией?

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
    }
}

Семантически я думаю, что второй кажется правильным, но если есть несколько IHostedService s, могут ли они работать параллельно со второй формой?

Редактировать 1

Я также пишу пример программы, которая иллюстрирует, что размещенные сервисы сами по себе не запускаются как отдельные потоки.

Сообщение "Waiting for signal.." не будет записано в консоли, пока я не наберу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;
        }
    }
}

1 Ответ

0 голосов
/ 10 июня 2019

Просто реализуйте его, используя async / await, как показано во втором примере.Нет необходимости в дополнительных Thread.

. Примечание: Thread следует использовать только для взаимодействия COM;В наши дни существуют гораздо лучшие решения для любого другого случая использования Thread.Как только вы наберете new Thread, у вас уже есть устаревший код.

...