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
  • 处理每个请求需要5秒钟。每个请求之间的延迟时间应为1秒。例如,如果您按下按钮2次,每次延迟1秒:首先,我们预计处理第一次按下按钮需要5秒,然后延迟1秒,最后,我们预计最后一次按下按钮需要5秒(第二次按下)
  • 为此,我正在使用
    排队后台任务
    项目中的
    点火和遗忘
    方式,当我只处理一个摄像头时,它工作正常

    但是项目的新要求是,后台任务应该处理多个摄像头。这意味着每个摄像头有一个队列,根据我上面描述的那个家伙,队列应该并行工作

    例如,如果我们有两个设备
    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 =>