ここで説明するようなキューに入れられたバックグラウンドタスクを使用するASP.NETコアWebAPIがあります。
私は、提供されたコードのサンプルを使用して追加したIBackgroundTaskQueue
、BackgroundTaskQueue
とQueuedHostedService
まったく同じ記事で説明します。
私の場合、次のようにStartup.cs
1つのQueuedHostedService
インスタンスのみを登録しています。services.AddHostedService<QueuedHostedService>();
WebApiのコントローラーからのタスクは、キューに入れられてからデキューされ、によって1つずつ実行されQueuedHostedService
ます。
着信タスクをデキューして実行する複数のバックグラウンド処理スレッドを許可したいと思います。私が思いつくことができる最も簡単な解決策はQueuedHostedService
、私のに複数のインスタンスを登録することStartup.cs
です。つまり、次のようなものです。
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;
}
}
あなたには、サービスを登録する必要がConfigureServices
上のStartup
クラス。
...
services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
services.AddHostedService<QueuedHostedService>();
...
さらに、構成内のスレッド数を設定できます(appsettings.json
)
...
"App": {
"MaxNumOfParallelOperations": 4
}
...
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加