C# 在.net core的后台服务中并行处理多个队列
我使用一些C# 在.net core的后台服务中并行处理多个队列,c#,.net-core,parallel-processing,queue,background-service,C#,.net Core,Parallel Processing,Queue,Background Service,我使用一些WIFI设备,比如照相机 我实施的基本原则是: 有人按下按钮 该按钮调用我的webapi端点 我的webapi端点调用相机的API之一(通过HttpRequest) 处理每个请求需要5秒钟。每个请求之间的延迟时间应为1秒。例如,如果您按下按钮2次,每次延迟1秒:首先,我们预计处理第一次按下按钮需要5秒,然后延迟1秒,最后,我们预计最后一次按下按钮需要5秒(第二次按下) 为此,我正在使用排队后台任务以项目中的点火和遗忘方式,当我只处理一个摄像头时,它工作正常 但是项目的新要求是,后台任务
WIFI
设备,比如照相机
我实施的基本原则是:
webapi
端点webapi
端点调用相机的API
之一(通过HttpRequest
)排队后台任务
以项目中的点火和遗忘
方式,当我只处理一个摄像头时,它工作正常
但是项目的新要求是,后台任务应该处理多个摄像头。这意味着每个摄像头有一个队列,根据我上面描述的那个家伙,队列应该并行工作
例如,如果我们有两个设备camera-001
和camera-002
和两个连接按钮btn-cam-001
和btn-cam-002
,按下顺序(每次按下后延迟0.5秒):2X btn-cam-001和1X btn-cam-002
真正发生的是FIFO
。首先处理btn-cam-001
的请求,然后处理btn-cam-002
我期望和需要的是:Camera-002
不应等待接收请求,对两个摄像头的第一个请求001
/002
应在同一时间处理(基于exmaple)。每个摄像头都有自己的队列和流程
问题是如何在.NetCore 3.1中实现这一点?
谢谢你的帮助
我当前的后台服务:
public class QueuedHostedService : BackgroundService
{
public IBackgroundTaskQueue TaskQueue { get; }
private readonly ILogger _logger;
public QueuedHostedService(IBackgroundTaskQueue taskQueue, ILoggerFactory loggerFactory)
{
TaskQueue = taskQueue;
_logger = loggerFactory.CreateLogger<QueuedHostedService>();
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Queued Hosted Service is starting.");
while (!cancellationToken.IsCancellationRequested)
{
var workItem = await TaskQueue.DequeueAsync(cancellationToken);
try
{
await workItem(cancellationToken);
}
catch (Exception exception)
{
_logger.LogError(exception, $"Error occurred executing {nameof(workItem)}.");
}
}
_logger.LogInformation("Queued Hosted Service is stopping.");
}
}
每个摄像头可以有一个BackgroundTaskQueue,而不是一个BackgroundTaskQueue。您可以将队列存储在字典中,将摄像头作为键:
public IDictionary<IDevice, IBackgroundTaskQueue> TaskQueues { get; }
您能否显示当前强制执行1秒延迟的代码?在调用TaskQueue.QueueBackgroundWorkItem
方法之前是否强制执行该方法?请注意,ExecuteAsync
方法在取消时的行为似乎不一致。返回的任务
可以转换为声明的已取消
(如果取消发生在等待
的任何阶段),或者转换为随机完成
状态(如果取消发生在IsCancellationRequested
检查while
循环中)@TheodorZoulias谢谢你的回复。我更新了帖子。而不是Thread.Sleep(TimeSpan.FromSeconds(1))代码>可以考虑更轻量级的代码>等待任务。Delay(TimeSp. FromSeconds(1));,以避免阻塞线程池
线程。@TheodorZoulias感谢您提供的宝贵提示。我会申请所有。。。Task.Delay()是我想要做的。谢谢你的回复。我尝试了几乎两种方法并应用了您提到的更改,但都没有成功。第一种方法是在控制器中应用所有这些更改。但由于IBackgroundTaskQueue是单例的,所以我得到了相同的结果。另一种方式让我很困惑。后台服务.cs中的IDictionary,而不是IBackgroundTaskQueue{get;}。问题是服务如何知道摄像头是一把钥匙?因为我需要从dic中检索正确的backgroundtaskqueue,以便退出队列并执行任务。你能给我举个例子吗?(我或多或少使用了这个链接)@peymangilmour我想你知道节目开始时你有多少个摄像头。您可以在服务启动时使用摄像头填充字典:TaskQueues.Add(camera1,new BackgroundTaskQueue())
等。顺便说一句,BackgroundTaskQueue
类似乎是异步队列的一个非常原始的实现。如果我处在你的位置,我更愿意使用。也有。是的,我同意。。。我将尝试使用频道。再次感谢。
[HttpPost("hit")]
public ActionResult TurnOnAsync([FromBody] HitRequest request, CancellationToken cancellationToken = default)
{
try
{
var camera = ConfigurationHelper.GetAndValidateCamera(request.Device, _configuration);
_taskQueue.QueueBackgroundWorkItem(async x =>
{
await _cameraRelayService.TurnOnAsync(request.Device, cancellationToken);
Thread.Sleep(TimeSpan.FromSeconds(1));
});
return Ok();
}
catch (Exception exception)
{
_logger.LogError(exception, "Error when truning on the lamp {DeviceName}.", request.Device);
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
}
public IDictionary<IDevice, IBackgroundTaskQueue> TaskQueues { get; }
_taskQueues[camera].QueueBackgroundWorkItem(async x =>