我有一个生产者/消费者流程。消费对象具有ID属性(类型为整数),我想一次只消耗一个具有相同ID的对象。我怎么能这样做?
也许我可以做这样的事情,但我不喜欢它(创建了太多的对象,而每天只有一两个具有相同ID的消息可以被消耗而且锁定(_lockers)有点耗费时间:< / p>
private readonly Dictionary<int,object> _lockers = new Dictionary<int,object>();
private object GetLocker(int id)
{
lock(_lockers)
{
if(!_lockers.ContainsKey(id))
_lockers.Add(id,new object());
return _lockers[id];
}
}
private void Consume(T notif)
{
lock(GetLocker(notif.ID))
{
...
}
}
enter code here
注意:同样的问题,ID属性是string类型(在那个cas中我可以锁定string.Internal(currentObject.ID)
答案 0 :(得分:12)
正如评论中所指出的,一种方法是拥有一个固定的锁池(比如32),并采用ID模32来确定要采取的锁。这会导致一些错误的锁共享。 32是从空中挑选的数字 - 这取决于你的ID值分布,消费者数量等等。
答案 1 :(得分:2)
您可以让您的ID对每个对象都是唯一的吗?如果是这样,您可以只对对象本身应用锁定。
答案 2 :(得分:2)
首先关闭,
你有没有想过确定lock(_lockers)
确实是一个瓶颈?因为如果没有破坏,请不要修理它。
编辑:我没有仔细阅读,这是关于创建的(大)辅助对象的数量 我认为达米恩对此有一个好主意,我将把这一点留下来:
关于
注意:与ID相同的问题 属性是字符串的类型(在那里 也许我可以锁定 string.Internal(currentObject.ID)
不,不好主意。你可以锁定一个字符串但是你必须担心他们可能会被拘禁。很难确定它们是独一无二的。
答案 3 :(得分:0)
请参阅How to: Synchronize a Producer and a Consumer Thread (C# Programming Guide)
除了简单的预防 用锁同时访问 关键字,进一步同步 由两个事件对象提供。一个是 用于向工作线程发出信号 终止,另一个使用 生产者线程发信号给 新项目具有的消费者线程 已被添加到队列中。这两个 事件对象封装在一个 类叫SyncEvents。这允许 要传递给对象的事件 代表消费者和 生产者很容易解决。
- 编辑 -
我写回来的simple code snippet;看看这是否有帮助。我认为这就是weismat指向的目标?
- 编辑 -
如何关注:
创建一个对象,比如CCustomer,它会持有:
将举行
现在检查以下内容
if(!_lockers.ContainsKey(id))
_lockers.Add(id,new CCustomer(/**bInProgress=true**/));
return _lockers[id]; **//here you can check the bInProgress value and respond accordingly**.
答案 4 :(得分:0)
我会将同步的FIFO队列视为所有生成对象的单独类/单例 - 生产者将对象排队并且消费者出列 - 因此实际对象不再需要任何同步。然后在实际对象之外完成同步。
答案 5 :(得分:0)
如何从ID对象池中分配ID并锁定这些ID?
创建项目时:
var item = CreateItem();
ID id = IDPool.Instance.Get(id);
//assign id to object
item.ID = id;
ID池创建并维护共享ID实例:
class IDPool
{
private Dictionary<int, ID> ids = new Dictionary<int, ID>();
public ID Get(int id)
{
//get ID from the shared pool or create new instance in the pool.
//always returns same ID instance for given integer
}
}
然后锁定ID,它现在是您的Consume方法中的引用:
private void Consume(T notif)
{
lock(notif.ID)
{
...
}
}
这不是最佳解决方案,只能将问题排除在不同的位置 - 但如果您认为自己对锁具有压力,则可以使用此方法获得性能提升(例如,您可以在单个方面创建对象)线程,你不需要同步ID池。