[英]ASP .Net Core Queued background tasks parallel processing
我有一個 ASP .NET 核心 Web API 使用此處描述的排隊后台任務。
我使用了提供的代碼示例,並完全按照文章中的描述添加了IBackgroundTaskQueue
、 BackgroundTaskQueue
和QueuedHostedService
。
在我的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
。
這是一個基本的實現。 我假設您使用的是此處描述的相同IBackgroundTaskQueue
和BackgroundTaskQueue
。
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.