C# 在并行执行中对任务进行分组,以防止同时执行具有相同groupingID的消息

C# 在并行执行中对任务进行分组,以防止同时执行具有相同groupingID的消息,c#,task-parallel-library,easynetq,C#,Task Parallel Library,Easynetq,我有一个使用EasyNetQ订阅服务器从RabbitMQ队列检索消息的使用者服务。处理每条消息需要数十秒的时间,我需要并行运行它们,以确保能够跟上生产者的进度。但是,每条消息都有一个属性,称之为groupingId。重要的是,不能同时执行具有相同groupingId的任务,因为这会导致资源冲突 很可能有数百个GroupingID,在通常情况下,任何时候都不会有太多具有相同Id的消息。但是,数据可能是突发的,导致数百个相同Id的集群同时发生 我想也许第三方物流数据流可能是一个很好的适合,但我不太熟

我有一个使用EasyNetQ订阅服务器从RabbitMQ队列检索消息的使用者服务。处理每条消息需要数十秒的时间,我需要并行运行它们,以确保能够跟上生产者的进度。但是,每条消息都有一个属性,称之为groupingId。重要的是,不能同时执行具有相同groupingId的任务,因为这会导致资源冲突

很可能有数百个GroupingID,在通常情况下,任何时候都不会有太多具有相同Id的消息。但是,数据可能是突发的,导致数百个相同Id的集群同时发生


我想也许第三方物流数据流可能是一个很好的适合,但我不太熟悉它,也不知道如何实现我所需要的。任何指导都将不胜感激。

创建分组ID字典并锁定它们

首先,在某处创建字典,可能作为成员变量

ConcurrentDictionary<int,object> _locks = new ConcurrentDictionary<int, object>();

这会阻止处理相同的groupingId消息。然而,仅仅丢弃消息并不是一个真正的选项。我的第一个方法是一个BlockingCollection对象字典。但它看起来非常笨拙。我不知道为什么在你的评论中会出现“丢弃”这个词——我的代码中没有丢弃任何东西的内容。我道歉。你说得对,我没有正确阅读你的代码。我认为这个解决方案对我来说确实可行,而且比其他任何方法都简单得多。我唯一关心的是锁的数量和我最终可能遇到的阻塞线程的数量,但解决这个问题的唯一方法是测试它。是的,这是一个蛮力解决方案,会导致大量的锁定和阻塞。另一种方法是建立10个线程和10个阻塞集合,并根据组ID中的最后一个数字为每个集合分配消息——诸如此类。这可能会执行得更好,但取决于消息传递系统的实现细节。一个想法可能是使用一个键控异步锁,基本上是一个
SemaphoreSlim
s的字典。您可以在这里找到一些实现:下面是一个Polly/TPL数据流方法:。
if (!_locks.ContainsKey(message.GroupingID))
{
    _locks.TryAdd(message.GroupingID, new object());
}
lock (_locks[message.GroupingID])
{
    ProcessMessage(message);
}