簡體   English   中英

ASP.Net Core Queued 后台任務並行處理

[英]ASP .Net Core Queued background tasks parallel processing

我有一個 ASP .NET 核心 Web API 使用此處描述的排隊后台任務。

我使用了提供的代碼示例,並完全按照文章中的描述添加了IBackgroundTaskQueueBackgroundTaskQueueQueuedHostedService

在我的Startup.cs中,我只注冊了一個QueuedHostedService實例,如下所示: services.AddHostedService<QueuedHostedService>();

來自 WebApi 的 controller 的任務被排隊,然后由QueuedHostedService執行。

我希望允許多個后台處理線程出列並執行傳入的任務。 我能想到的最直接的解決方案是在我的Startup.cs中注冊多個QueuedHostedService實例。 即,像這樣:

 int maxNumOfParallelOperations;
 var isValid = int.TryParse(Configuration["App:MaxNumOfParallelOperations"], out maxNumOfParallelOperations);

 maxNumOfParallelOperations = isValid && maxNumOfParallelOperations > 0 ? maxNumOfParallelOperations : 2;

 for (int index = 0; index < maxNumOfParallelOperations; index++) 
 {
    services.AddHostedService<QueuedHostedService>();
 }

我還注意到,由於BackgroundTaskQueue中的信號量, QueuedHostedService實例並不是一直都在工作,而是只有在隊列中有新任務可用時才會喚醒。

這個解決方案在我的測試中似乎工作得很好。

但是,在這個特定的用例中——它真的是一個有效的、推薦的並行處理解決方案嗎?

您可以使用具有多個線程的IHostedService來使用IBackgroundTaskQueue

這是一個基本的實現。 我假設您使用的是此處描述的相同IBackgroundTaskQueueBackgroundTaskQueue

public class QueuedHostedService : IHostedService
{
    private readonly ILogger _logger;

    private readonly Task[] _executors;
    private readonly int _executorsCount = 2; //--default value: 2
    private CancellationTokenSource _tokenSource;
    public IBackgroundTaskQueue TaskQueue { get; }

    public QueuedHostedService(IBackgroundTaskQueue taskQueue,
        ILoggerFactory loggerFactory,
        IConfiguration configuration)
    {
        TaskQueue = taskQueue;
        _logger = loggerFactory.CreateLogger<QueuedHostedService>();

        if (ushort.TryParse(configuration["App:MaxNumOfParallelOperations"], out var ct))
        {
            _executorsCount = ct;
        }
        _executors = new Task[_executorsCount];
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Queued Hosted Service is starting.");

        _tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

        for (var i = 0; i < _executorsCount; i++)
        {
            var executorTask = new Task(
                async () =>
                {
                    while (!cancellationToken.IsCancellationRequested)
                    {
#if DEBUG
                    _logger.LogInformation("Waiting background task...");
#endif
                    var workItem = await TaskQueue.DequeueAsync(cancellationToken);

                        try
                        {
#if DEBUG
                        _logger.LogInformation("Got background task, executing...");
#endif
                        await workItem(cancellationToken);
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex,
                                "Error occurred executing {WorkItem}.", nameof(workItem)
                            );
                        }
                    }
                }, _tokenSource.Token);

            _executors[i] = executorTask;
            executorTask.Start();
        }

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Queued Hosted Service is stopping.");
        _tokenSource.Cancel(); // send the cancellation signal

        if (_executors != null)
        {
            // wait for _executors completion
            Task.WaitAll(_executors, cancellationToken);
        }

        return Task.CompletedTask;
    }
}

您需要在Startup class 時在ConfigureServices中注冊服務。

...
services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
services.AddHostedService<QueuedHostedService>();
...

此外,您可以在配置中設置線程數( appsettings.json

...
"App": {
    "MaxNumOfParallelOperations": 4
}
...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM